2+线程的自编Mutex

时间:2015-09-06 07:15:03

标签: c multithreading pthreads posix mutex

我已经编写了以下代码,到目前为止,在我的所有测试中,似乎我已经为我的4个线程编写了一个有效的Mutex,但是我希望得到别人对我的有效性的看法。解。

typedef struct Mutex{
    int turn;
    int * waiting;
    int num_processes;
} Mutex;

void enterLock(Mutex * lock, int id){   
    int i;
    for(i = 0; i < lock->num_processes; i++){
        lock->waiting[id] = 1;
        if (i != id && lock->waiting[i])
            i = -1;
        lock->waiting[id] = 0;
    }
    printf("ID %d Entered\n",id);
}

void leaveLock(Mutex * lock, int id){
    printf("ID %d Left\n",id);
    lock->waiting[id] = 0;
}

void foo(Muted * lock, int id){
    enterLock(lock,id);
    // do stuff now that i have access
    leaveLock(lock,id);
}

4 个答案:

答案 0 :(得分:2)

我觉得有必要在这里写一个答案,因为问题很好,考虑到它可以帮助其他人理解互斥的一般问题。在您的情况下,您可以很长时间地隐藏此问题,但您无法避免此问题。归结为:

01  /* pseudo-code */
02  if (! mutex.isLocked())
03        mutex.lock();

您始终需要在行0203之间切换线程。因此,有一种情况可能会导致两个线程发现mutex未锁定并在此之后被中断...仅在稍后恢复并单独锁定此互斥锁。您将有两个线程同时进入临界区。

实现可靠互斥所必需的是一个原子操作,它可以测试一个条件,同时设置一个值而不会有任何机会被同时中断。

01  /* pseudo-code */
02  while (! test_and_lock(mutex));

只要此test_and_lock函数无法中断,您的实现就是安全的。在之前,C没有提供这样的内容,因此pthreads的实现需要使用,例如汇编或特殊编译器内在函数。使用,最终会有一个&#34;标准&#34;写这样的原子操作的方法,但我不能在这里给出一个例子,因为我没有经验这样做。对于一般用途,pthreads库将为您提供所需的信息。

编辑当然,这仍然是简化的 - 在多处理器方案中,您需要确保即使是内存访问也是互斥的。

答案 1 :(得分:1)

我在您的代码中看到的问题:

mutex背后的想法是提供互斥,意味着当thread_a位于关键部分时,thread_b必须等待(如果他也想要进入){ {1}}。

此等待部分应在thread_a函数中实现。但是你所拥有的是enterLock循环,它可能会在for从关键部分完成之前结束,因此thread_a也可以进入,因此你不能互相排斥。

解决问题的方法:

Peterson's algorithm或Dekker(more complicated)为例,他们所做的是thread_b所谓的busy waiting基本上是{{ 1}}循环说: while

答案 2 :(得分:1)

你完全无视内存模型的话题。除非您使用的是具有顺序一致内存模型的计算机(当前没有PC CPU),否则您的代码不正确,因为一个线程执行的任何存储不一定立即对其他CPU可见。但是,这似乎是您代码中的假设。

底线:使用操作系统提供的现有同步原语或POSIX或Win32 API等运行时库,不要试图变得聪明并自己实现。除非您在并行编程方面有多年的经验以及对CPU架构的深入了解,否则您最终可能会遇到错误的实现。调试并行程序可能是地狱......

答案 3 :(得分:0)

enterLock()返回后,Mutex对象的状态与调用函数之前的状态相同。因此,即使在第一个线程释放它调用leaveLock()之前,它也不会阻止第二个线程进入相同的Mutex对象。没有相互排斥。