不久之前,我测试了信号量使用简单程序的方式,其中3个线程(每个线程由其函数调用)以输出的方式同步:
<ONE><TWO><THREE><ONE><TWO><THREE><ONE><TWO><THREE><ONE><TWO><THREE><ONE><TWO><THREE>...
(感兴趣的每个人的代码here或作为参考点)
我尝试使用条件变量重新创建相同的程序,并且事情变得非常棘手
。#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
pthread_cond_t condvar1=PTHREAD_COND_INITIALIZER;
pthread_cond_t condvar2=PTHREAD_COND_INITIALIZER;
pthread_cond_t condvar3=PTHREAD_COND_INITIALIZER;
pthread_mutex_t MUT=PTHREAD_MUTEX_INITIALIZER;
int loop=3;
void *one()
{
int i;
for(i=0;i<loop;i++)
{
pthread_mutex_lock(&MUT);
if(pthread_cond_signal(&condvar3)==0)
pthread_cond_wait(&condvar1, &MUT);
pthread_mutex_unlock(&MUT);
printf("<ONE>");
pthread_mutex_lock(&MUT);
pthread_cond_signal(&condvar2);
pthread_mutex_unlock(&MUT);
}
return(NULL);
}
void *two()
{
int i;
for(i=0;i<loop;i++)
{
pthread_mutex_lock(&MUT);
if(pthread_cond_signal(&condvar1)==0)
pthread_cond_wait(&condvar2, &MUT);
pthread_mutex_unlock(&MUT);
printf("<TWO>");
pthread_mutex_lock(&MUT);
pthread_cond_signal(&condvar3);
pthread_mutex_unlock(&MUT);
}
return(NULL);
}
void *three()
{
int i;
for(i=0;i<loop;i++)
{
pthread_mutex_lock(&MUT);
if(pthread_cond_signal(&condvar2)==0)
pthread_cond_wait(&condvar3, &MUT);
pthread_mutex_unlock(&MUT);
printf("<THREE>");
pthread_mutex_lock(&MUT);
pthread_cond_signal(&condvar1);
pthread_mutex_unlock(&MUT);
}
return(NULL);
}
int main(int argc, char *argv[])
{
pthread_t ena, dyo, tria;
pthread_create(&ena, NULL, one, NULL);
pthread_create(&dyo, NULL, two, NULL);
pthread_create(&tria, NULL, three, NULL);
pthread_join(ena, NULL);
pthread_join(dyo, NULL);
pthread_join(tria, NULL);
return 0;
}
基本上我遇到了初始化第一个变量(condvar1)的问题,以便开始同步,因为非常方便的sem_init()
是不可能的。
后来我虽然除此之外,我可以检查之前的条件变量(if(pthread_cond_signal(&previousconditionvariable)==0)
)是否已经释放其锁定然后我可以锁定 next 条件变量。
但是,对于condvar1没有正确的初始化(因为我搜索了here,here,here,here),当然没有输出。
有关初始化的想法和/或检查先前'条件变量信号的提示吗?
更新:删除了之前的ifs并在他们的位置获得了一个标志:
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
pthread_cond_t condvar1=PTHREAD_COND_INITIALIZER;
pthread_cond_t condvar2=PTHREAD_COND_INITIALIZER;
pthread_cond_t condvar3=PTHREAD_COND_INITIALIZER;
pthread_mutex_t MUT=PTHREAD_MUTEX_INITIALIZER;
int flag;
int loop=3;
void *one()
{
int i;
for(i=0;i<loop;i++)
{
pthread_mutex_lock(&MUT);
if(flag==1)
{
pthread_cond_wait(&condvar1, &MUT);
}
pthread_mutex_unlock(&MUT);
printf("<ONE>");
flag=2;
pthread_mutex_lock(&MUT);
pthread_cond_signal(&condvar2);
pthread_mutex_unlock(&MUT);
}
return(NULL);
}
void *two()
{
int i;
for(i=0;i<loop;i++)
{
pthread_mutex_lock(&MUT);
if(flag==2)
{
pthread_cond_wait(&condvar2, &MUT);
}
pthread_mutex_unlock(&MUT);
printf("<TWO>");
flag=3;
pthread_mutex_lock(&MUT);
pthread_cond_signal(&condvar3);
pthread_mutex_unlock(&MUT);
}
return(NULL);
}
void *three()
{
int i;
for(i=0;i<loop;i++)
{
pthread_mutex_lock(&MUT);
if(flag==3)
{
pthread_cond_wait(&condvar3, &MUT);
}
pthread_mutex_unlock(&MUT);
printf("<THREE>");
flag=1;
pthread_mutex_lock(&MUT);
pthread_cond_signal(&condvar1);
pthread_mutex_unlock(&MUT);
}
return(NULL);
}
int main(int argc, char *argv[])
{
pthread_t ena, dyo, tria;
flag=1;
pthread_create(&ena, NULL, one, NULL);
pthread_create(&dyo, NULL, two, NULL);
pthread_create(&tria, NULL, three, NULL);
pthread_join(ena, NULL);
pthread_join(dyo, NULL);
pthread_join(tria, NULL);
return 0;
}
现在输出为<THREE><THREE><THREE><TWO><TWO><TWO><ONE><ONE><ONE>
答案 0 :(得分:1)
此代码是对代码的简化,我相信它可以按预期工作。有一个单一的线程函数,由其参数控制。也只有一个条件变量。 turn
变量指示它转向哪个线程。 turn
的操作是在线程锁定互斥锁时完成的,因此没有其他线程同时使用它。同样在互斥锁被锁定时完成打印,以确保它在正确的时间发生。
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
static pthread_cond_t condvar = PTHREAD_COND_INITIALIZER;
static pthread_mutex_t MUT = PTHREAD_MUTEX_INITIALIZER;
static int turn;
static int loop = 3;
struct Control
{
int thread_num;
const char *msg;
};
static void *thread_func(void *arg)
{
struct Control *ctl = arg;
printf("Thread %d (%s)\n", ctl->thread_num, ctl->msg);
for (int i = 0; i < loop; i++)
{
pthread_mutex_lock(&MUT);
while (turn != ctl->thread_num)
pthread_cond_wait(&condvar, &MUT);
printf("<%s>", ctl->msg);
turn++;
if (turn > 3)
turn = 1;
pthread_cond_broadcast(&condvar);
pthread_mutex_unlock(&MUT);
}
return(NULL);
}
int main(void)
{
pthread_t ena, dyo, tri;
struct Control ctl[] =
{
{ 1, "ONE" },
{ 2, "TWO" },
{ 3, "THREE" },
};
srand(time(0));
turn = rand() % 3 + 1;
printf("%d goes first\n", turn);
pthread_create(&ena, NULL, thread_func, &ctl[0]);
pthread_create(&dyo, NULL, thread_func, &ctl[1]);
pthread_create(&tri, NULL, thread_func, &ctl[2]);
pthread_join(ena, NULL);
pthread_join(dyo, NULL);
pthread_join(tri, NULL);
putchar('\n');
return 0;
}
在我的MacBook Pro上运行macOS Sierra 10.12.4(使用GCC 7.1.0,而不是编译器在这里非常重要),我从连续运行中获得了这样的结果(但是在两者之间存在不确定的多秒差距运行):
2 goes first
Thread 1 (ONE)
Thread 2 (TWO)
Thread 3 (THREE)
<TWO><THREE><ONE><TWO><THREE><ONE><TWO><THREE><ONE>
3 goes first
Thread 1 (ONE)
Thread 2 (TWO)
Thread 3 (THREE)
<THREE><ONE><TWO><THREE><ONE><TWO><THREE><ONE><TWO>
3 goes first
Thread 1 (ONE)
Thread 2 (TWO)
Thread 3 (THREE)
<THREE><ONE><TWO><THREE><ONE><TWO><THREE><ONE><TWO>
1 goes first
Thread 1 (ONE)
Thread 2 (TWO)
Thread 3 (THREE)
<ONE><TWO><THREE><ONE><TWO><THREE><ONE><TWO><THREE>
3 goes first
Thread 2 (TWO)
Thread 1 (ONE)
Thread 3 (THREE)
<THREE><ONE><TWO><THREE><ONE><TWO><THREE><ONE><TWO>
请注意,有一次,线程2在线程1之前报告。
我希望可以像原始代码一样使用三个条件变量,但这似乎有些过分。
pthread调用的错误检查是......不存在。这在示例代码中是好的,至少在它工作时,但通常不是一个好主意。