#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
pthread_t node[4];
pthread_mutex_t token;
pthread_cond_t cond;
int id=0;
void *func(int n)
{
int count = 0;
while (count < 10){
pthread_mutex_lock(&token);
while (id != n){
printf("Whoops not my turn, id=%d\n",n);
pthread_cond_wait(&cond, &token);}
//if (id == n){
count += 1;
printf ("My turn! id= %d\n",n);
printf("count %d\n", count);
if (id == 3){
id = 0;}
else{
id += 1;}
//}else{
// printf("Not my turn! id=%d\n",n);}
// pthread_mutex_unlock(&token);
// sleep(2);}
pthread_mutex_unlock(&token);
pthread_cond_signal(&cond);}
printf ("ID=%d has finished\n",n);
return(NULL);
}
int main()
{
int i;
pthread_mutex_init(&token,NULL);
pthread_cond_init(&cond,NULL);
for(i=0;i<4;i++)
pthread_create(&node[i],NULL,(void *)func,(void *)i);
for(i=0;i<4;i++)
pthread_join(node[i],NULL);
pthread_mutex_destroy(&token);
return 0;
}这是我的代码,它是一个使用线程的C程序。我不认为它的目的需要知道在这里,但我会给出一个例子,我有问题。
假设使用id 1的线程(在func中由n定义)获取互斥体,并返回"My!id=1“。当调用mutex_unlock和cond_signal时,获取互斥对象的下一个线程实际上将再次为id 1的线程,它将打印“不要轮到我,id=1”。只有这样,使用id 2的线程才会得到互斥体,并打印"My!id=2",但是当id =2的线程在那之后得到互斥的时候。这是我的程序输出:
Whoops not my turn, id=1
Whoops not my turn, id=2
Whoops not my turn, id=3
My turn! id= 0
count 1
Whoops not my turn, id=0
My turn! id= 1
count 1
Whoops not my turn, id=1
My turn! id= 2
count 1
Whoops not my turn, id=2
My turn! id= 3
count 1
Whoops not my turn, id=3
My turn! id= 0
count 2
Whoops not my turn, id=0
My turn! id= 1
count 2
Whoops not my turn, id=1
My turn! id= 2
count 2
Whoops not my turn, id=2
My turn! id= 3
count 2
Whoops not my turn, id=3
My turn! id= 0
count 3
Whoops not my turn, id=0
My turn! id= 1
count 3
Whoops not my turn, id=1
My turn! id= 2
count 3
Whoops not my turn, id=2
My turn! id= 3
count 3
Whoops not my turn, id=3
My turn! id= 0
count 4
Whoops not my turn, id=0
My turn! id= 1
count 4
Whoops not my turn, id=1
My turn! id= 2
count 4
Whoops not my turn, id=2
My turn! id= 3
count 4
Whoops not my turn, id=3
My turn! id= 0
count 5
Whoops not my turn, id=0
My turn! id= 1
count 5
Whoops not my turn, id=1
My turn! id= 2
count 5
Whoops not my turn, id=2
My turn! id= 3
count 5
Whoops not my turn, id=3
My turn! id= 0
count 6
Whoops not my turn, id=0
My turn! id= 1
count 6
Whoops not my turn, id=1
My turn! id= 2
count 6
Whoops not my turn, id=2
My turn! id= 3
count 6
Whoops not my turn, id=3
My turn! id= 0
count 7
Whoops not my turn, id=0
My turn! id= 1
count 7
Whoops not my turn, id=1
My turn! id= 2
count 7
Whoops not my turn, id=2
My turn! id= 3
count 7
Whoops not my turn, id=3
My turn! id= 0
count 8
Whoops not my turn, id=0
My turn! id= 1
count 8
Whoops not my turn, id=1
My turn! id= 2
count 8
Whoops not my turn, id=2
My turn! id= 3
count 8
Whoops not my turn, id=3
My turn! id= 0
count 9
Whoops not my turn, id=0
My turn! id= 1
count 9
Whoops not my turn, id=1
My turn! id= 2
count 9
Whoops not my turn, id=2
My turn! id= 3
count 9
Whoops not my turn, id=3
My turn! id= 0
count 10
ID=0 has finished
My turn! id= 1
count 10
ID=1 has finished
My turn! id= 2
count 10
ID=2 has finished
My turn! id= 3
count 10
ID=3 has finished如您所见,每次成功后,线程打印“我的回合!”之后,它将得到互斥,并造成“呼呼而不是我的回合!”。我不明白为什么在我调用pthread_cond_signal时会发生这种情况,它应该会指示另一个线程在当前线程重新获得互斥对象之前醒来。请帮助我找到这个解决方案,因为我认为有重要的东西,我错过了。如果我没有解释,请随时向我索取更多的信息。非常感谢您的时间!
发布于 2018-10-05 07:40:39
@rcgldr已经给出了一个非常好的解释所涉及的时间。如果您想增加给另一个线程一个机会的可能性,请尝试添加一个对yield的调用,这将给调度程序选择不同线程的机会,尽管这也不是一个保证。
发布于 2018-10-05 00:18:05
在Linux (可能还有posix系统)的情况下,无法保证互斥锁请求得到服务的顺序。当互斥锁被解锁时,操作系统不会强制进行上下文切换,因此当前运行的线程继续其循环并再次锁定互斥锁。我不知道您是否可以通过p线程接口更改线程优先级,但如果可以的话,您可以只增加线程"(n)%4“的优先级,而当线程"(n)%4”运行时,它会将其优先级设置为正常的,并将线程"(n+1)%4“设置为更高的优先级。
在Windows使用其本机互斥体的情况下,显然锁请求的顺序在队列或等效的队列中被跟踪,因此当当前运行的线程循环回锁请求时,Windows将切换到互斥锁请求队列中的第一个线程。我不知道这是否有记录,但我已经证实它是这样工作的。我不知道Windows中的线程互斥体是否会以这种方式工作。
一个可能的替代方案是每个线程一个互斥,但我不知道这是否会导致任何问题,取决于操作系统。每个线程使用一个信号量应该有效。
附带注意,如果使用条件变量,您可以得到一个虚假的唤醒,并将需要处理这种情况。
但是,如果使用本机Windows同步类型,如互斥、信号量、.,则不会发生虚假的唤醒。
对于一些操作系统,如Linux,这些问题已经足够了,一些高端的多线程应用程序安装了内核级驱动程序,以实现内核时间自旋锁以避免这些问题。
https://stackoverflow.com/questions/52656580
复制相似问题