以下代码片段被写入打印偶数,一个线程和奇数与其他线程。
#include <stdio.h>
#include <pthread.h>
#include <stdlib.h>
#define LIMIT 100
int counter;
pthread_mutex_t mutex1 = PTHREAD_MUTEX_INITIALIZER;
void* function(void *p)
{
int expected = *(int *)p;
while(expected < LIMIT)
{
pthread_mutex_lock( &mutex1 );
while (counter != expected);
printf("%d\n", counter++);
expected += 2;
pthread_mutex_unlock( &mutex1 );
};
exit(0);
}
int main(int argc, char *argv[])
{
pthread_t thread1, thread2;
int counter = 0;
int expected_0 = 0, expected_1 = 1;
pthread_create(&thread1, NULL, function, (void *)&expected_0);
pthread_create(&thread2, NULL, function, (void *)&expected_1);
pthread_join(thread1, NULL);
pthread_join(thread2, NULL);
return 0;
}
但是当执行时它会显示0的输出并挂起
amit@ubuntu:~$ gcc -pthread even_odd.c
amit@ubuntu:~$ ./a.out
0
任何人都可以指出我的情况吗?
还有更好的逻辑来完成这项任务吗?
答案 0 :(得分:1)
这是互斥锁死锁的经典案例。
让我们看看细节:
在这里,您按顺序创建了两个线程,第一个期望counter
为0,第二个期望counter
为1.然后每个线程将增加一个并且使另一个线程具有预期值
现在没有必要在线程thread1
之前创建线程thread2
,然后线程thread1
将始终在线程thread2
之前执行。这完全取决于您的OS调度程序,并且您对它的控制很少。
因此当thread2
在thread1
之前开始执行时,它将获得mutex1
并将开始在while (counter != expected);
语句中等待。现在,当thread1
开始执行时,mutex1
会阻止thread2
,因为它已被counter
获取。现在,没有人可以更新void* function(void *p)
{
int expected = *(int *)p;
while(expected < LIMIT)
{
pthread_mutex_lock( &mutex1 );
if (counter == expected) {
printf("%d\n", counter++);
expected += 2;
}
pthread_mutex_unlock( &mutex1 );
};
}
。这将导致死锁。
您应该使用以下代码作为线程函数();
{{1}}
这里
答案 1 :(得分:1)
这里有几个问题。
主要的一点是,当一个线程应该等待counter
达到其expected
值时,它不会解锁互斥锁以允许另一个线程继续进行。这修复了(添加<stdbool.h>
并编译为C99):
void* function(void *p)
{
int expected = *(int *)p;
while(expected < LIMIT)
{
bool my_turn = false;
while (!my_turn)
{
pthread_mutex_lock( &mutex1 );
my_turn = (counter == expected);
pthread_mutex_unlock( &mutex1 );
}
pthread_mutex_lock( &mutex1 );
printf("%d\n", counter++);
pthread_mutex_unlock( &mutex1 );
expected += 2;
};
上面的代码锁定互斥锁以检查计数器,然后再次将其解锁并在计数器未达到预期值时循环,以便另一个线程可以运行。然后再次锁定互斥锁以再次访问counter
。
另一个问题是调用exit(0)
会导致两个线程在其中一个线程完成后立即退出。您可能只想从函数返回:
return NULL;
}
编写循环的另一种方法是:
while (true)
{
pthread_mutex_lock( &mutex1 );
if (counter == expected)
break;
pthread_mutex_unlock( &mutex1 );
}
printf("%d\n", counter++);
pthread_mutex_unlock( &mutex1 );
expected += 2;
理解这一点稍微复杂一些,但避免在计数器达到预期值时解锁并重新锁定互斥锁。相反,它会突破循环,使互斥锁被锁定,打印值,然后解锁互斥锁。