我正在开发一个项目,其中包含用户定义的线程数目。我有一个在每个线程中运行的while循环,但我需要所有的线程在while循环结束时等待彼此。棘手的是,一些线程并非都通过循环以相同的次数结束。
void *entryFunc(void *param)
{
int *i = (int *)param;
int nextPrime;
int p = latestPrime;
while(latestPrime < testLim)
{
sem_wait(&sem);
nextPrime = findNextPrime(latestPrime);
if(nextPrime != -1)
{
latestPrime = nextPrime;
p = latestPrime;
}
else
{
sem_post(&sem);
break;
}
sem_post(&sem);
if(p < 46341)
{
incrementNotPrimes(p);
}
/*
sem_wait(&sem2);
doneCount++;
sem_post(&sem2);
while(go != 1);
sem_wait(&sem2);
doneCount--;
//sem_post(&sem3);
sem_post(&sem2);
*/
}
return NULL;
}
代码块被注释掉的地方是我上次尝试解决这个问题的一部分。这就是所有功能都需要彼此等待的地方。我有一种感觉,我错过了一些简单的东西。
答案 0 :(得分:1)
如果您的问题是在每个线程上,while循环具有不同的迭代次数,并且一些线程在退出循环后永远不会到达同步点,则可以使用屏障。请查看 here 以获取示例。
但是,在退出每个线程后,您需要减少屏障处的线程数。等待屏障将在计数线程数达到该点后结束。
因此,每次线程完成时都需要更新barrier对象。并确保你原子地这样做。
答案 1 :(得分:0)
正如我在评论中提到的,在这种情况下你应该使用障碍而不是信号量,因为它应该更容易实现(障碍的设计正是为了解决这个问题)。但是,您仍然可以使用信号量和一点算术
算术:你的目标是让所有线程执行相同的代码路径,但不知何故,完成其任务的最后一个线程应该唤醒所有其他线程。实现这一目标的一种方法是在函数末尾 一个原子计数器,每个线程将减少,如果计数器达到0
,则线程只调用sem_post
{{ 1}}根据需要释放所有等待的线程,而不是像其他线程一样发出sem_wait
。
第二种方法,这次只使用一个信号量,也是可能的。由于我们无法区分其他线程的最后一个线程,所有线程必须对信号量执行相同的操作,即尝试释放所有人,但也等待最后一个。因此,我们的想法是将信号量初始化为(1-n)*(n+1)
,这样每个n-1
第一个线程都会在通过n+1
调用sem_post
来唤醒他们的朋友时失败,但仍然努力获得信号量0
。然后最后一个线程也会这样做,将信号量值推送到n+1
,从而释放锁定的线程,并留出空间让它也执行sem_wait
并立即释放。
void *entryFunc(void *param)
{
int *i = (int *)param;
int nextPrime;
int p = latestPrime, j;
while(latestPrime < testLim){
nextPrime = findNextPrime(latestPrime);
if(nextPrime != -1)
{
latestPrime = nextPrime;
p = latestPrime;
}
if(p < 46341)
{
incrementNotPrimes(p);
}
}
for (j=0;j<=THREAD_COUNT;j++)
sem_post(&sem);
sem_wait(&sem);
return NULL;
}
这种方法的问题在于它没有处理如何在两次使用之间重置信号量(如果你的程序需要重复这种机制,它将需要重置信号量值,因为它将结束在成功执行此代码后,为1
。