sleep linux阻塞,linux – 为什么sleep()获取pthread_mutex_lock后会阻塞整个程序?

在我的测试程序中,我启动了两个线程,每个线程只执行以下逻辑:

1) pthread_mutex_lock()

2) sleep(1)

3) pthread_mutex_unlock()

但是,我发现经过一段时间后,两个线程中的一个将永远阻塞pthread_mutex_lock(),而另一个线程正常工作.这是一种非常奇怪的行为,我认为这可能是一个潜在的严重问题.通过Linux手册,获取pthread_mutex_t时不禁止sleep().所以我的问题是:这是一个真正的问题还是我的代码中有任何错误?

以下是测试程序.在代码中,第一个线程的输出定向到stdout,而第二个线程定向到stderr.所以我们可以检查这两个不同的输出,看看线程是否被阻塞.

我在linux内核(2.6.31)和(2.6.9)上测试过它.两个结果都是一样的.

//======================= Test Program ===========================

#include

#include

#include

#include

#define THREAD_NUM 2

static int data[THREAD_NUM];

static int sleepFlag = 1;

static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;

static void * threadFunc(void *arg)

{

int* idx = (int*) arg;

FILE* fd = NULL;

if (*idx == 0)

fd = stdout;

else

fd = stderr;

while(1) {

fprintf(fd, "\n[%d]Before pthread_mutex_lock is called\n", *idx);

if (pthread_mutex_lock(&mutex) != 0) {

exit(1);

}

fprintf(fd, "[%d]pthread_mutex_lock is finisheded. Sleep some time\n", *idx);

if (sleepFlag == 1)

sleep(1);

fprintf(fd, "[%d]sleep done\n\n", *idx);

fprintf(fd, "[%d]Before pthread_mutex_unlock is called\n", *idx);

if (pthread_mutex_unlock(&mutex) != 0) {

exit(1);

}

fprintf(fd, "[%d]pthread_mutex_unlock is finisheded.\n", *idx);

}

}

// 1. compile

// gcc -o pthread pthread.c -lpthread

// 2. run

// 1) ./pthread sleep 2> /tmp/error.log # Each thread will sleep 1 second after it acquires pthread_mutex_lock

// ==> We can find that /tmp/error.log will not increase.

// or

// 2) ./pthread nosleep 2> /tmp/error.log # No sleep is done when each thread acquires pthread_mutex_lock

// ==> We can find that both stdout and /tmp/error.log increase.

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

if ((argc == 2) && (strcmp(argv[1], "nosleep") == 0))

{

sleepFlag = 0;

}

pthread_t t[THREAD_NUM];

int i;

for (i = 0; i < THREAD_NUM; i++) {

data[i] = i;

int ret = pthread_create(&t[i], NULL, threadFunc, &data[i]);

if (ret != 0) {

perror("pthread_create error\n");

exit(-1);

}

}

for (i = 0; i < THREAD_NUM; i++) {

int ret = pthread_join(t[i], (void*)0);

if (ret != 0) {

perror("pthread_join error\n");

exit(-1);

}

}

exit(0);

}

这是输出:

在程序启动的终端上:

root@skyscribe:~# ./pthread sleep 2> /tmp/error.log

[0]Before pthread_mutex_lock is called

[0]pthread_mutex_lock is finisheded. Sleep some time

[0]sleep done

[0]Before pthread_mutex_unlock is called

[0]pthread_mutex_unlock is finisheded.

...

在另一个终端上看到文件/tmp/error.log

root@skyscribe:~# tail -f /tmp/error.log

[1]Before pthread_mutex_lock is called

并且没有新的行从/tmp/error.log中输出

解决方法:

这是使用互斥锁的错误方法.线程不应该持有互斥锁的时间超过它不拥有它的时间,特别是如果它在按住互斥锁时休眠.锁定互斥锁没有FIFO保证(出于效率原因).

更具体地说,如果线程1在线程2等待它时解锁互斥锁,则它使线程2可运行但这不会强制调度程序抢占线程1或使线程2立即运行.最有可能的是,它不会因为线程1最近睡过了.当线程1随后到达pthread_mutex_lock()调用时,通常会允许它立即锁定互斥锁,即使有一个线程正在等待(并且实现可以知道它).当线程2在此之后唤醒时,它会发现互斥锁已经锁定并重新进入休眠状态.

最好的解决方案是不要长时间持有互斥锁.如果无法做到这一点,请考虑将需要锁定的操作移动到单个线程(不需要锁定)或使用条件变量唤醒正确的线程.

标签:unix,linux,pthreads

来源: https://codeday.me/bug/20190530/1185605.html

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值