pthreads - 在 pthread_mutex_t 中存储指针

标签 pthreads mutex

我正在开发一个 C 语言项目,该项目涉及通过重写 pthread.h 创建用户级线程库。我目前正在研究互斥函数。

在我的实现中,我将互斥体存储为结构的链接列表。我想在 pthread_mutex_init 中做的是将指向新创建的互斥体元素的指针存储在 pthread_mutex_t 互斥体变量中。但这可能吗?这是我的一些代码,以便您了解我想要做什么:

typedef struct mutexList
{
    int mid;
    struct mutexList *prevMutex;
    struct mutexList *nextMutex;
    int locked;
    struct queueItem *owner;
    struct blockedThread *blockedHead;
    struct blockedThread *blockedTail;
} mutexElement;

int mutexCounter = 0;

mutexElement *mutexHead = NULL;
mutexElement *mutexTail = NULL;

int pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t *attr)
{
    mutexElement *newMutex = (mutexElement *) malloc(sizeof(mutexElement));

    fprintf(stdout, "***LOG: Creating new mutex.\n");

    if(newMutex == NULL)
        return ENOMEM;
    newMutex->mid = mutexCounter;
    mutexCounter++;
    newMutex->locked = 0;
    newMutex->nextMutex = NULL;
    newMutex->blockedHead = NULL;
    newMutex->blockedTail = NULL;

    if(mutexHead == NULL)
        mutexHead = newMutex;

    if(mutexTail != NULL)
        mutexTail->nextMutex = newMutex;

    mutexTail = newMutex;

    mutex = (&newMutex);

    return 0;
}

最佳答案

我认为您的总体想法可行,但您的特定示例至少存在一些问题:

  • 您的mutexCounter , mutexHeadmutexTail项目不是以线程安全的方式处理的(此类库的一个重要属性)
  • 线路 mutex = (&newMutex);毫无意义-mutex是一个参数,它是用户参数的副本。当你的函数返回时,mutex根本不复存在;它不会返回给调用者。
  • 甚至试图返回 &newMutex首先对用户来说是一个问题:newMutex是一个局部变量,该变量将在函数返回时过期。将指向它的指针存储在应该存在于当前函数调用持续时间之后的内容中是行不通的。

请注意,我并不是说上面列出的是详尽的问题 - 它们只是突然出现的问题。

你可以制作pthread_mutex_t输入 struct mutexList* 的 typedef并放置 newMutex 的值(不是 newMutex 的地址)在 *mutex 中自 mutex将是 struct mutexList** 。用户的pthread_mutex_t变量将包含指向链接列表上的结构的指针。

如果用户忘记调用pthread_mutex_destroy()并让他的pthread_mutex_t变量超出范围,然后 struct mutexList分配的元素永远不会被释放,但这是一个用户错误,您实际上无能为力。

就互斥体初始化而言,您仍然需要考虑另一个大问题 - 静态初始化。允许用户执行以下操作:

// the following is at file scope, so it has static duration
pthread_mutex_t myMutex = PTHREAD_MUTEX_INITIALIZER;

在这种情况下,用户不需要调用pthread_mutex_init() ——事实上,这样做是错误的。您的库将需要在首次使用(或等效的东西)时检测并执行这些静态初始化互斥体所需的任何适当的动态初始化。并且您必须以线程安全的方式执行此操作 - 第一次使用不仅允许在任意线程上完成,这些静态互斥体的主要用例之一是允许立即对互斥体进行争用(例如由恰好访问它的第一个线程对其他静态数据执行更复杂的初始化)。

总而言之,我认为保留私有(private)互斥数据结构的容器并拥有用户的pthread_mutex_t的一般方法变量本质上是指向容器中适当项目的指针(或其他一些间接引用)就可以了。然而,有很多复杂的细节 - 特别是确保你的函数是线程安全的 - 需要考虑和设计。

示例中存在的各种问题表明迄今为止的设计还没有得到足够的考虑。这可能没问题——也许你刚刚开始这样做;只是不要低估您需要给予这些东西的对细节的关注。

关于pthreads - 在 pthread_mutex_t 中存储指针,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10201987/

相关文章:

c++ - 如何缓解过于频繁调用的函数?

c++ - 多生产者-消费者执行的效率

c++ - 我们需要多少个内存屏障来实现 Peterson 锁?

c++ - 另一个线程安全队列实现

ruby - 如何最好地保持作业队列清理重试/重复作业(使用 sidekiq 和 redis-semaphore)

c - posix regcomp 和 regexec 线程安全吗?具体来说,在 GNU libc 上?

c - 使用共享内存时遇到一些问题

c++ - 在 C++ 中为函数计时

C 多线程字数统计

检查当前时间的数据结构,如果找到则删除?