这部分代码是否需要互斥锁?

时间:2011-03-19 20:08:54

标签: c++ multithreading mutex semaphore

我正在尝试实现粗线程中断。

经常检查'interruptRequested'变量。在操作系统课程中,我们了解了饥饿 - 这可能在这里或在类似的情况下吗?我知道示例程序的行为与我在运行它时的预期相同,但它可能只是一个侥幸。

以下是我正在做的简化版本:

//Compile with -lpthread

#include <iostream>
#include <signal.h>
#include <sys/types.h>
#include <time.h>
#include <unistd.h>
#include <pthread.h>

using namespace std;

bool interruptRequested;
pthread_mutex_t spamMutex;
void *Spam(void *); 

int main(int argc, char *argv[])
{   

pthread_t tid; 

interruptRequested = false;

unsigned long long int timeStarted = time(NULL);
pthread_create(&tid, NULL, Spam, NULL);
unsigned long long int difference = 0;


while (true)
{
    pthread_yield();
    difference = (time(NULL) - timeStarted);
    if ( difference >= 5)//Spam the terminal for 5 seconds
    {
        //while (pthread_mutex_trylock(&spamMutex));
        interruptRequested = true;
        //pthread_mutex_unlock(&spamMutex);
        break;
    }


}

return 0;
}

void *Spam (void *arg)
{
while (true)
{
    //while (pthread_mutex_trylock(&spamMutex));
    if (interruptRequested == true)
    {
        //pthread_mutex_unlock(&spamMutex);
        break;
    }
    //pthread_mutex_unlock(&spamMutex);
    cout << "I'm an ugly elf" << endl;
    pthread_yield();
}

interruptRequested = false;
pthread_exit (0); 
}

实际上,在实际代码中我没有使用时差方法。我的程序将收到来自服务器的消息,此时我需要中断该线程。

3 个答案:

答案 0 :(得分:1)

如上所述,此代码不一定能保证有效,因为编译器可能会优化对工作线程内部interruptRequested的检查,因为它永远不会写入函数内部。这意味着生成的代码可能只有一个while (true)循环(或类似的东西)。

为了防止这种情况发生,您需要确保编译器识别出该变量可能在其他地方被修改。您可以通过标记interruptRequested volatile来执行此操作,这表明编译器不应该对其进行优化。使用互斥锁也是一个好主意,因为大多数编译器都足够聪明,可以识别使用互斥锁表示互斥锁内部引用的变量可以在外部修改。

答案 1 :(得分:0)

我认为通常共享数据应该使用互斥锁处理。

在这种特定情况下,只有一个线程更新控制变量,因此使用互斥锁可能过多。您可以在几毫秒的活动循环中进行时间休眠,以使主循环不时处于活动状态。

答案 2 :(得分:0)

是的,您必须首先使用互斥锁来保护对相应块中的interruptRequested的读写操作。

即使出现按预期工作,也可能实际上没有。软件无法接受99%的成功率。同样,你的测试程序是微不足道的 - 在现实世界中它会(无声地或神秘地)失败的可能性很大。

使用volatile(或在许多情况下是原子)作为锁的替代是的想法。这个模型最终会失败,虽然它常常出现在轻负载下正常工作。有一些极端情况,但你应该放弃volatile的关联,以取代使用锁定的正确设计。实际上,您可以通过将interruptRequested设为int并仅使用递增/递减来测试此操作。在重载下 - 你可以快速超过[0 ... 1]。

在声明/读/写interruptRequested时,你会经常使用volatile和/或atomics(同样,我建议使用int / inc / dec / bounds检查,特别是在你学习的时候)。如果读取和写入都被锁定(在这种情况下应该是这样),使用原子读/写将无济于事。

关于您的计划,条件(pthread_cond_t)可能是一个不错的选择。