2011-03-19 91 views
1

我正在尝试执行粗线程中断。这部分代码是否需要互斥锁?

'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); 
} 

其实,在真正的代码,我不使用的时间差的方式。我的程序将从服务器收到一条消息,此时我需要中断该线程。

回答

0

是的,你必须首先使用互斥来保护读取和写入interruptRequested,在各块。

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

使用volatile(或原子,在很多情况下)作为锁的替代是不好的想法。这种模式最终会失败,虽然它往往出现在轻负载下正常工作。有几个角落的情况下,但你应该放弃挥发性的协会是替代正确的设计,使用锁定。实际上你可以通过使interruptRequestedint并仅使用递增/递减来测试。在重负载下 - 您可以快速超过[0 ... 1]。

你会经常使用挥发性和/或原子公司的声明时/读/写interruptRequested(再次,我建议一个int/INC/DEC /边界检查,尤其是在你学习)。如果读取和写入都被锁定(在这种情况下应该是这样),使用原子读取/写入将无济于事。

关于你的程序,条件(pthread_cond_t)可能是一个不错的选择。

1

书面,该代码并不一定保证能工作,因为编译器可能会优化掉在检查interruptRequested工作线程内,因为它从来没有的功能里面写。这意味着生成的代码可能只有一个while (true)循环(或者与之相当的东西)。

为了防止这种情况发生,您需要确保编译器识别出该变量可能在其他地方被修改过。你可以通过标记interruptRequestedvolatile来做到这一点,它向编译器表明它不应该被优化掉。使用互斥锁也是一个好主意,因为大多数编译器都足够聪明,可以认识到使用互斥锁表示互斥体内引用的变量可能会在外部修改。

+0

+1是的,使用volatile属性是一个好主意 – fabrizioM 2011-03-19 20:16:09

0

我认为一般共享数据应该用互斥锁来处理。

在这种特定情况下,只有一个线程更新控制变量,所以它可能使用互斥锁太多。您可以在几毫秒的主动循环中进行时间休眠,以使主循环时常激活。