- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我尝试在 pthread_mutex 上创建一个包装器,该包装器维护当前线程持有的所有互斥锁的列表。但是,我也使用了某些库代码,对此我不可能使用这个包装器。有什么办法可以得到这个通用 pthread_mutexes 的列表吗?
FWIW,我使用的是 Linux 主机。
最佳答案
您可以插入(例如通过 LD_PRELOAD
和 <dlfcn.h>
)pthread_mutex_lock()
, pthread_mutex_trylock()
, 和 pthread_mutex_unlock()
使用您自己的函数调用底层函数,但也维护每个线程数组/持有的互斥地址链。 (您可以使用 GCC 提供的 __thread
存储类关键字,相当于 C11 _Thread_local
来声明每个线程的变量。)
这是一个经过验证的工作示例。
生成文件 ,构建插入库和示例程序:
# SPDX-License-Identifier: CC0-1.0
CC := gcc
CFLAGS := -Wall -Wextra -O2
LDFLAGS := -pthread -ldl
BINS := libheld.so example
.PHONY: all clean run
all: clean $(BINS)
clean:
rm -f *.o $(BINS)
run: libheld.so example
env LD_PRELOAD=./libheld.so ./example
%.o: %.c
$(CC) $(CFLAGS) -c $^
libheld.so: libheld.c
$(CC) $(CFLAGS) -fPIC $^ -shared -Wl,-soname,$@ -ldl -o $@
example: example.o held.o
$(CC) $(CFLAGS) $^ $(LDFLAGS) -o $@
请注意,Makefile 中的缩进必须使用 Tabs,因此如果您复制粘贴上述内容,则需要修复缩进,例如通过运行
sed -e 's|^ *|\t|' -i Makefile
.
// SPDX-License-Identifier: CC0-1.0
#define _GNU_SOURCE
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
#include <dlfcn.h>
#include <errno.h>
static int (*original_lock)(pthread_mutex_t *) = NULL;
static int (*original_trylock)(pthread_mutex_t *) = NULL;
static int (*original_unlock)(pthread_mutex_t *) = NULL;
static int held_err = 0;
static __thread size_t held_max = 0;
static __thread size_t held_num = 0;
static __thread pthread_mutex_t **held_ptr = NULL;
int libheld_errno(void)
{
return __atomic_load_n(&held_err, __ATOMIC_SEQ_CST);
}
size_t libheld_count(void)
{
return held_num;
}
pthread_mutex_t *libheld_mutex(size_t i)
{
return (i < held_num) ? held_ptr[i] : NULL;
}
int pthread_mutex_lock(pthread_mutex_t *m)
{
int (*lock)(pthread_mutex_t *);
__atomic_load(&original_lock, &lock, __ATOMIC_SEQ_CST);
if (!lock) {
lock = dlsym(RTLD_NEXT, "pthread_mutex_lock");
if (!lock) {
__atomic_store_n(&held_err, ENOSYS, __ATOMIC_SEQ_CST);
return ENOSYS;
}
__atomic_store(&original_lock, &lock, __ATOMIC_SEQ_CST);
}
int retval = lock(m);
if (retval)
return retval;
if (held_num >= held_max) {
const int saved_errno = errno;
const size_t temp_max = (held_num | 127) + 121;
void *temp_ptr;
temp_ptr = realloc(held_ptr, temp_max * sizeof held_ptr[0]);
if (!temp_ptr) {
__atomic_store_n(&held_err, ENOMEM, __ATOMIC_SEQ_CST);
errno = saved_errno;
return 0;
}
held_max = temp_max;
held_ptr = temp_ptr;
}
held_ptr[held_num++] = m;
return 0;
}
int pthread_mutex_trylock(pthread_mutex_t *m)
{
int (*trylock)(pthread_mutex_t *);
__atomic_load(&original_trylock, &trylock, __ATOMIC_SEQ_CST);
if (!trylock) {
trylock = dlsym(RTLD_NEXT, "pthread_mutex_trylock");
if (!trylock) {
__atomic_store_n(&held_err, ENOSYS, __ATOMIC_SEQ_CST);
return ENOSYS;
}
__atomic_store(&original_trylock, &trylock, __ATOMIC_SEQ_CST);
}
int retval = trylock(m);
if (retval)
return retval;
if (held_num >= held_max) {
const int saved_errno = errno;
const size_t temp_max = (held_num | 127) + 121;
void *temp_ptr;
temp_ptr = realloc(held_ptr, temp_max * sizeof held_ptr[0]);
if (!temp_ptr) {
__atomic_store_n(&held_err, ENOMEM, __ATOMIC_SEQ_CST);
errno = saved_errno;
return 0;
}
held_max = temp_max;
held_ptr = temp_ptr;
}
held_ptr[held_num++] = m;
return 0;
}
int pthread_mutex_unlock(pthread_mutex_t *m)
{
int (*unlock)(pthread_mutex_t *);
__atomic_load(&original_unlock, &unlock, __ATOMIC_SEQ_CST);
if (!unlock) {
unlock = dlsym(RTLD_NEXT, "pthread_mutex_unlock");
if (!unlock) {
__atomic_store_n(&held_err, ENOSYS, __ATOMIC_SEQ_CST);
return ENOSYS;
}
__atomic_store(&original_unlock, &unlock, __ATOMIC_SEQ_CST);
}
int retval = unlock(m);
if (retval)
return retval;
size_t i = 0;
while (i < held_num) {
if (held_ptr[i] == m) {
held_num--;
if (i < held_num) {
memmove(held_ptr + i, held_ptr + i + 1, (held_num - i) * sizeof held_ptr[0]);
}
} else {
i++;
}
}
return 0;
}
持有.c ,实现获取互斥量跟踪信息所需的接口(interface)(互斥量跟踪是否可用,当前线程持有多少个互斥量,以及这些互斥量的地址):
// SPDX-License-Identifier: CC0-1.0
#define _POSIX_C_SOURCE 200809L
#define _GNU_SOURCE
#include <stdlib.h>
#include <pthread.h>
#include <dlfcn.h>
#include <errno.h>
static int libheld_errno_default(void)
{
return ENOSYS;
}
static size_t libheld_count_default(void)
{
return 0;
}
static pthread_mutex_t *libheld_mutex_default(size_t i)
{
(void)i; /* Silences warning about unused parameter; generates no code. */
return NULL;
}
static int (*held_errno_func)(void) = NULL;
static size_t (*held_count_func)(void) = NULL;
static pthread_mutex_t *(*held_mutex_func)(size_t) = NULL;
int held_errno(void)
{
int (*errno_func)(void);
__atomic_load(&held_errno_func, &errno_func, __ATOMIC_SEQ_CST);
if (!held_errno_func) {
errno_func = dlsym(RTLD_DEFAULT, "libheld_errno");
if (!errno_func)
errno_func = libheld_errno_default;
__atomic_store(&held_errno_func, &errno_func, __ATOMIC_SEQ_CST);
}
return errno_func();
}
size_t held_count(void)
{
size_t (*count_func)(void);
__atomic_load(&held_count_func, &count_func, __ATOMIC_SEQ_CST);
if (!count_func) {
count_func = dlsym(RTLD_DEFAULT, "libheld_count");
if (!count_func)
count_func = libheld_count_default;
__atomic_store(&held_count_func, &count_func, __ATOMIC_SEQ_CST);
}
return count_func();
}
pthread_mutex_t *held_mutex(size_t i)
{
pthread_mutex_t *(*mutex_func)(size_t);
__atomic_load(&held_mutex_func, &mutex_func, __ATOMIC_SEQ_CST);
if (!mutex_func) {
mutex_func = dlsym(RTLD_DEFAULT, "libheld_mutex");
if (!mutex_func)
mutex_func = libheld_mutex_default;
__atomic_store(&held_mutex_func, &mutex_func, __ATOMIC_SEQ_CST);
}
return mutex_func(i);
}
注意,因为直到运行时我们才知道互斥跟踪是否可用以及插入库是否加载,我们需要使用
-ldl
) 链接就足够了。
// SPDX-License-Identifier: CC0-1.0
#ifndef HELD_H
#define HELD_H
#include <stdlib.h>
#include <pthread.h>
/* Returns zero if mutex tracking is available, nonzero otherwise. */
extern int held_errno(void);
/* Returns the number of mutexes held by the current thread. */
extern size_t held_count(void);
/* Returns a pointer to the i'th mutex (0 up to held_count()-1) held by the current thread. */
extern pthread_mutex_t *held_mutex(size_t);
#endif /* HELD_H */
示例.c ,显示了跟踪持有的互斥锁的示例:
// SPDX-License-Identifier: CC0-1.0
#define _POSIX_C_SOURCE 200809L
#define _GNU_SOURCE
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
#include <stdio.h>
#include <errno.h>
#include "held.h"
#ifndef LOCKS
#define LOCKS 5
#endif
void print_held(FILE *out)
{
if (!out)
out = stdout;
int err = held_errno();
if (err == ENOSYS) {
fprintf(out, "Mutex tracking is not available.\n");
return;
} else
if (err) {
fprintf(out, "Error in mutex tracking: %s.\n", strerror(err));
return;
}
size_t n = held_count();
if (n > 0) {
fprintf(out, "%zu %s held by current thread:\n", n, (n > 1) ? "mutexes" : "mutex");
for (size_t i = 0; i < n; i++) {
fprintf(out, "\t%p\n", held_mutex(i));
}
} else {
fprintf(out, "No mutexes held by current thread.\n");
}
}
int main(void)
{
pthread_mutex_t lock[LOCKS];
size_t i;
for (i = 0; i < LOCKS; i++)
pthread_mutex_init(lock + i, NULL);
for (i = 0; i < LOCKS; i++)
pthread_mutex_lock(lock + i);
print_held(stdout);
for (i = 0; i < LOCKS; i++)
pthread_mutex_unlock(lock + i);
print_held(stdout);
return EXIT_SUCCESS;
}
通过运行
make clean all
编译库和示例程序.
./example
,它只输出“互斥跟踪不可用”。
LD_PRELOAD=./libheld.so ./example
,它输出主线程持有的(默认5个)互斥锁。
ltrace -fttt -o logfile -e pthread_mutex_lock+pthread_mutex_trylock+pthread_mutex_unlock ./example
以便 ltrace 将每个 pthread_mutex_lock、pthread_mutex_trylock 和 pthread_mutex_unlock 调用记录到带有时间戳(自 Unix 纪元以来的秒数)的日志文件中。
关于c - 有没有办法找到当前 pthread 持有的 pthread_mutexes 列表?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/65904672/
来自 Java/C# 背景,我正在尝试实现一个空安全检查对象。以下代码尝试检查对象上是否确实存在颜色。如果有,我希望能够做一些事情(比如在形状上绘制颜色)。我希望能够将此颜色设置回 null (non
目前,我正在使用来自 Boost Vault 的类型安全枚举类: Which Typesafe Enum in C++ Are You Using? 我发现很难有一个父类指针来引用所有枚举类,因为 B
假设我设置了一个存储库。我希望有的用户可以推送,有的用户我想先过一遍推送的内容再批准。有条件推送之类的概念吗?待批准推送队列? 最佳答案 您本质上需要一个代码审查工具。 git 有一些,但最好的可能是
我使用 Windows 版 git bash 和 Beyond & Compare 作为我的差异工具(但同样的事情发生在任何外部差异工具上)。 我希望我的终端不要等待 difftool 退出以返回终端
这个问题在这里已经有了答案: SVN: Is there a way to mark a file as "do not commit"? (18 个回答) 8年前关闭。 在某些情况下,作为开发环境设
Jcombobox 可以保存 int 吗?因为我尝试了这个并收到错误。 int[] timeSched = new int[] {200,300,400,500}; JComboBox Jcombo1
最近,我开始为我的游戏制作 map 编辑器,遇到了一些问题,我已经解决了这些问题。我现在的问题是我有一个 JFrame (主界面)。在该 JFrame 中,我有一个 JScrollPane,其中包含我
ElementAdapter类 package com.example.sierendeelementeninbreda; import android.content.Context; import
我能以某种方式将 jquery 对象作为 javascript 对象的键吗? (编辑)..作为关键.. var $a = $("#a"); var $b = $("#b"); var c = {};
我分两步解码 jpeg。 检查边界,必要时确定比例。 在屏幕限制内解码。 public static Bitmap decodeSampledBitmapFromInputStream(InputSt
谁能告诉我为什么下面代码中 $mytextarea 的范围没有扩展到 getAnswerToo() 函数中? getAnswer() 之所以有效,是因为我明确选择了要更新的元素。但是,尝试使用全局“处
如果我有实现接口(interface) I 的类 A 并将它传递到需要接口(interface) I 的地方,例如传递给线程,将这会阻止 GC 对 A 类的实例进行垃圾回收?我想是的,但我该如何解决呢
我正在使用 Swift3 和 Xcode 8.3.3 我正在研究持有 UICollectionView 的 UITableViewCell。每个 CollectionView 单元格都需要执行 seg
我正在使用 CVMetalTextureCacheCreateTextureFromImage 从 CVImageBuffer(来自相机和播放器)创建一个 MTLTexture 以获得 CVMetal
我有三个类:HopBill、HopBillController 和 HopBillSheetController。 HopBill 创建一个包含 NSMutableArray 的对象。出于测试目的,我
一些 Powermock/Mockito 文章提到了使用 PowerMock.mockStaticPartial 方法 - 唯一的问题是我在任何地方都找不到它! 有谁知道它存在于哪个 Artifact
我有一个显示新闻条目详细信息的 ViewPager。您可以在 30 个条目之间来回滑动。这些条目中的每一个都是一个包含 ImageView 的 View 。此 ImageView 使用 Picasso
操作应尽量保持与原始输入类型相同的答案,因此如果持有者以 Double 开头,则结果也应该是 double。 如果输入包含不同数字类型的持有者,那么它应该自动加宽等。 应该有一种带有 getter 的
比如,如果我编写如下所示的代码: const int & const_value = 10; 与看起来像这样的代码相比,我有什么优势: int value = 10; 或 const int cons
我在 Windows XP(代码:Block,MinGW)和 Ubuntu(11.04,G++)上运行了以下两段代码 我无法运行以下代码 #include using namespace std;
我是一名优秀的程序员,十分优秀!