我正在开发一个 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
,mutexHead
和mutexTail
项目不是以线程安全的方式处理的(此类库的一个重要属性) - 线路
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/