したがって、変数を0から100にインクリメントする2つのスレッドを持つこのプログラムがあり、正常に動作します。
#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
スレッドにサイクルを保証させたい場合は、N(スレッド数)を法とするカウンターが特定のIDになるまで、その特定のID以外になるまで、スレッドを待機させる必要があります。IDが2つある場合、1つでなければ、もう1つでなければなりません。しかし、3つある場合、2つのケースが壊れ、1つのケースが待機します。スケジューラーは、解放したい2つのスペアスレッドのどちらかを自由に選択できます。
しかし、これを変更すると:
while (contor %3 == id)
これに:
while (contor %3 != id)
指定されたスレッドがそのIDを法とする値のみを書き込むように強制します。
ただし、これだけでは不十分です。また、すべてのウェイターを起こす必要があります。以前は、スレッドが2つしかない場合、常に同じウェイターがいました。アクティブなスレッドではない「他の人」です。これはpthread_cond_signal
特定のターゲットスレッド(実行されていない唯一のスレッド)に送信され、当然、次のスレッドでもあります。
スレッドが3つ以上ある場合、によって起動される可能性のある単一のスレッドpthread_cond_signal
が、Nidを法とするcontorを持つスレッドではない可能性があります。実際、スレッドが多いほど、これが発生する可能性が高くなります。その場合、スレッドは待機状態に戻りますが、待機中の他のユーザーは再び起動されません。これを偶然に任せたくはありません。次のウェイターが信号を受信することを確認するために、すべてのウェイターが起こされていることを確認してください。
別の場所に送信するだけでこれに対処しないでくださいpthread_cond_signal
。代わりに、代わりにブロードキャストを送信します。これを変更します。
pthread_cond_signal(&cond);
これに:
pthread_cond_broadcast(&cond);
これにより、アクティブに待機しているすべてのスレッドが最終的に見た目に亀裂を生じ、Nを法としてcontor
一致contor
するスレッドは、バンプ、印刷、次のブロードキャストの送信、および待機に戻る機会を確実に得ることができます。
したがって、コードへの最小限の変更は次のようになります。
#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
余分な2つの出力は、ceiling-break条件をチェックするコードがcvar-predicateループの前にあるためです。それは後でなければなりませんが、私はあなたが対処するためにそれを残します。
ただし、これを行うと、タスクで複数のスレッドを緩めるという目的が最終的に無効になることに注意してください。理想的には、あなたが欲しいどんな実際にそうするように作業を実行するためにスレッドが利用できます。作業が単一のグローバルにのみ影響するということは、スレッド化の本当の目的をいくらか無効にします(明らかに、スレッド化を使用して100までカウントすることはありません。ループ内の単一のスレッドは、そのために理想的です)。
とにかく、プログラムの要約版が以下に表示されます。値を変更N_THREADS
し、N_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;
}
この記事はインターネットから収集されたものであり、転載の際にはソースを示してください。
侵害の場合は、連絡してください[email protected]
コメントを追加