2016-08-30 54 views
2

所以我有这个程序有2个线程从0增加到100个变量,它工作正常。条件变量程序适用于2个线程但不适用于3

#include<stdio.h> 
#include<stdlib.h> 
#include<semaphore.h> 
#include<pthread.h> 

int contor; 

pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; 
pthread_cond_t cond = PTHREAD_COND_INITIALIZER; 

void *incrementare(void *args) { 
    int id = (int)args; 
    while(1) { 
     pthread_mutex_lock(&mutex); 
     if (contor >= 100) { 
      pthread_cond_signal(&cond); 
      pthread_mutex_unlock(&mutex); 
      pthread_exit(NULL); 
     } 

     while (contor %2 == id) { 
     pthread_cond_wait(&cond,&mutex); 
     } 

     contor++; 
     printf("Thread %d increment: %d\n",id,contor); 


     pthread_cond_signal(&cond); 
     pthread_mutex_unlock(&mutex); 
    } 
} 

int main(void) { 
    pthread_t th1, th2,th3; 

    if(pthread_create(&th1, NULL, &incrementare, (void *)0) < 0) { 
     perror("Error!\n"); 
     exit(1); 
    } 
    if(pthread_create(&th2, NULL, &incrementare, (void *)1) < 0) { 
     perror("Error!\n"); 
     exit(2); 
    } 


    pthread_join(th1, NULL); 
    pthread_join(th2, NULL); 

    pthread_mutex_destroy(&mutex); 
    pthread_cond_destroy(&cond); 

    return 0; 
} 

的结果是这样的:

Thread 1 increment: 1 
Thread 0 increment: 2 
Thread 1 increment: 3 
Thread 0 increment: 4 
Thread 1 increment: 5 
Thread 0 incre.. and so on ,which is nice. 

但问题是,当我尝试用3个线程,它不再工作,因为他们再来找随机。我只做了3个改变,我不知道问题是什么。

#include<stdio.h> 
#include<stdlib.h> 
#include<semaphore.h> 
#include<pthread.h> 

int contor; 

pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; 
pthread_cond_t cond = PTHREAD_COND_INITIALIZER; 

void *incrementare(void *args) { 
    int id = (int)args; 
    while(1) { 
     pthread_mutex_lock(&mutex); 
     if (contor >= 100) { 
      pthread_cond_signal(&cond); 
      pthread_mutex_unlock(&mutex); 
      pthread_exit(NULL); 
     } 

     while (contor %3 == id) { 
     pthread_cond_wait(&cond,&mutex); 
     } 

     contor++; 
     printf("Thread %d increment: %d\n",id,contor); 


     pthread_cond_signal(&cond); 
     pthread_mutex_unlock(&mutex); 
    } 
} 

int main(void) { 
    pthread_t th1, th2,th3; 

    if(pthread_create(&th1, NULL, &incrementare, (void *)0) < 0) { 
     perror("Error!\n"); 
     exit(1); 
    } 
    if(pthread_create(&th2, NULL, &incrementare, (void *)1) < 0) { 
     perror("Error!\n"); 
     exit(2); 
    } 
    if(pthread_create(&th3, NULL, &incrementare, (void *)2) < 0) { 
     perror("Error!\n"); 
     exit(3); 
    } 



    pthread_join(th1, NULL); 
    pthread_join(th2, NULL); 
     pthread_join(th3, NULL); 


    pthread_mutex_destroy(&mutex); 
    pthread_cond_destroy(&cond); 

    return 0; 
} 

它应该做同样的权利?现在只有3。为什么它不工作?这是如何工作的

Thread 2 increment: 1 
Thread 2 increment: 2 
Thread 1 increment: 3 
Thread 1 increment: 4 
Thread 2 increment: 5 
Thread 1 increment: 6 
+4

与您的问题无关,但如果您声明函数返回值,则应该返回一个值。即使你忽略返回的值。 –

+2

也与您的问题无关,但[pthread_create'](http://man7.org/linux/man-pages/man3/pthread_create.3.html)函数错误时不会返回“-1”。成功时返回'0',否则返回错误代码。这意味着你检查错误是错误的。 –

+5

在相同级别的优先级任务中,OS按内核喜欢的方式调度线程。如果你想强加一个特定的序列,你应该编码约束。 – LPs

回答

2

如果你想线程以保证循环,你需要做一个线程等待,直到模N计数器(线程数)是特定 ID,直到它是什么但是那个具体的id。有两个ID,如果它不是一个,它必须是另一个。但有三个,有两个破案,一个等待。 调度程序可以自由选择要释放的那两个备用线程中的哪一个。

但是,如果你改变了这个:

while (contor %3 == id) 

这样:

while (contor %3 != id) 

你会强制执行给定的线程将写值被模其ID。

但是,这还不够。你还需要唤醒全部服务员。之前,当你只有两个线程时,总是有同一个服务员:“另一个人”不是活动线程。这个pthread_cond_signal将被定向到一个特定的目标线程(唯一没有运行的线程),它自然也是下一个线程。

如果有三个或更多线程,则可能由pthread_cond_signal潜在唤醒的单线程可能不是具有contor模N id的那个线程。事实上,你拥有的线程越多,发生这种情况的可能性就越大。在这种情况下,线程回到等待状态,但没有其他人等待再次启动。你不想让这个机会。确保全部服务员醒来确保下一个将获得信号。

不是解决这个只是发送另一个pthread_cond_signal的地方。相反,发送一个广播,而不是:更改此:

pthread_cond_signal(&cond); 

这样:

pthread_cond_broadcast(&cond); 

这将确保所有积极等待的线程最终在看着contor得到裂纹,而匹配contor的一个模N将有机会撞击,打印,发送下一个广播,然后回头等待。

因此,为了你的代码的最小变化将是:

#include<stdio.h> 
#include<stdlib.h> 
#include<stdint.h>  // added for intptr_t 
#include<inttypes.h> // added for printf formatter for intptr_t 
#include<pthread.h> 

int contor; 

pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; 
pthread_cond_t cond = PTHREAD_COND_INITIALIZER; 

void *incrementare(void *args) { 
    intptr_t id = (intptr_t)args; // proper way to pass an integer via thread param 
    while(1) { 
     pthread_mutex_lock(&mutex); 
     if (contor >= 100) { 
      pthread_cond_broadcast(&cond); 
      pthread_mutex_unlock(&mutex); 
      pthread_exit(NULL); 
     } 

     while (contor %3 != id) { 
     pthread_cond_wait(&cond,&mutex); 
     } 

     contor++; 
     printf("Thread %"PRIdPTR " increment: %d\n",id,contor); 


     pthread_cond_broadcast(&cond); 
     pthread_mutex_unlock(&mutex); 
    } 
    return NULL; // should always have well-defined return value 
} 

int main(void) { 
    pthread_t th1, th2,th3; 

    if(pthread_create(&th1, NULL, &incrementare, (void *)0) < 0) { 
     perror("Error!\n"); 
     exit(1); 
    } 
    if(pthread_create(&th2, NULL, &incrementare, (void *)1) < 0) { 
     perror("Error!\n"); 
     exit(2); 
    } 
    if(pthread_create(&th3, NULL, &incrementare, (void *)2) < 0) { 
     perror("Error!\n"); 
     exit(3); 
    } 

    pthread_join(th1, NULL); 
    pthread_join(th2, NULL); 
    pthread_join(th3, NULL); 

    pthread_mutex_destroy(&mutex); 
    pthread_cond_destroy(&cond); 

    return 0; 
} 

结果如下:

Thread 0 increment: 1 
Thread 1 increment: 2 
Thread 2 increment: 3 
Thread 0 increment: 4 
Thread 1 increment: 5 
Thread 2 increment: 6 
Thread 0 increment: 7 
Thread 1 increment: 8 
Thread 2 increment: 9 
Thread 0 increment: 10 
.... 
Thread 0 increment: 97 
Thread 1 increment: 98 
Thread 2 increment: 99 
Thread 0 increment: 100 
Thread 1 increment: 101 
Thread 2 increment: 102 

See it live

额外的两个输出是因为代码检查的天花板中断条件为之前的 cvar-predicate循环。在之后应该是,但是我留给你解决。

但请记住,这样做最终会失去在任务上松动多个线程的目的。理想情况下,您希望任何线程可用于执行工作以实际执行此操作。你的工作只影响一个单一的全局,但却有损于线程的真正目的(显然你不会使用线程数到100;循环中的单个线程是理想的)。


无论如何,您的程序的精简版本如下所示。更改N_THREADSN_COUNT的值以查看输出的差异。

#include <stdio.h> 
#include <stdlib.h> 
#include <stdint.h> 
#include <inttypes.h> 
#include <pthread.h> 

#define N_THREADS 7 
#define N_COUNT 100 

int contor; // 0 

pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; 
pthread_cond_t cond = PTHREAD_COND_INITIALIZER; 

void *incrementare(void *args) 
{ 
    intptr_t id = (intptr_t)args; 
    pthread_mutex_lock(&mutex); 
    while(1) 
    { 
     while (contor < N_COUNT && contor % N_THREADS != id) 
      pthread_cond_wait(&cond, &mutex); 

     if (contor == N_COUNT) 
      break; 

     printf("Thread %"PRIdPTR" increment: %d\n", id, ++contor); 
     pthread_cond_broadcast(&cond); 
    } 
    pthread_mutex_unlock(&mutex); 
    return NULL; 
} 

int main(void) 
{ 
    pthread_t ar[N_THREADS]; 
    intptr_t id = 0; 

    for (int i=0; i<N_THREADS; ++i) 
    { 
     if(pthread_create(ar+i, NULL, &incrementare, (void *)id++) < 0) { 
      perror("Error!\n"); 
      exit(1); 
     } 
    } 

    for (int i=0; i<N_THREADS; ++i) 
     pthread_join(ar[i], NULL); 

    return 0; 
} 
+0

嘿,我试过你的第一个解决方案,但它没有工作。它给线程0增量:1然后停止,实际上它什么都不做,以某种方式停留在无限循环中。 –

+0

@HopelessWanderer是的,我忽略提到需要将您的信号更改为广播。原因很重要。阅读更新的答案。 – WhozCraig

+0

非常感谢!它现在工作! :d –

相关问题