2016-05-24 4 views
0

pthreadsを使用してマルチスレッドプログラムを作成しています。発想は単純です:Pthreads - 条件変数とmutexを持つプロデューサとコンシューマ - 結合エラーと奇妙なCout

  • カー(スレッド)
  • ガソリン供給(スレッド)
  • ガソリンスタンド(リソース)

両方の車とガソリンステーションは、いくつかの燃料容量を持っており、車の後にされましたガソリンスタンドを訪問する必要があります。ガソリンスタンドに燃料がなくなると、ガソリン供給スレッドが稼動し、資源を補充します。すべては、私がpthread_joinの代わりにpthread_exitを使用して、主な機能のスレッドを待つ必要があり、時には同じ車のためにcoutをダブルしなければならないということを除いて、うまくいくようです:"-----End of fuel-----"。 私はそれを正しくやっていますか?

構造体といくつかのグローバル変数:

#define initialFuel 100 
#define loop 10 

pthread_mutex_t mutex1, mutex2; 
pthread_cond_t isempty; 
PetrolDistributor petrolDistributor; 

struct Car { 
    int capacity = 10; 
    int petrol = 5; 
}; 

struct PetrolDistributor { 
    int petrol = initialFuel; 
    bool isEmpty = false; 
}; 

スレッド:

void * threadSupply(void *arg) 
{ 
    for(int i = 0; i<loop; i++) 
{ 
     pthread_mutex_lock(&mutex1); 

     while(!petrolDistributor.isEmpty) 
     { 
      pthread_cond_wait(&isempty, &mutex1); //When signal received, do below: 
      usleep(2000000); 
      petrolDistributor.petrol = initialFuel; //Refill petrol and change state 
      petrolDistributor.isEmpty = false; 
     } 
     pthread_mutex_unlock(&mutex1); 
    } 
} 

void * threadPetrolDriver(void *arg) 
{ 
    Car *car; 
    car = (Car*) arg; 

    for(int i = 0; i<loop; i++) 
    { 
     while(car->petrol > 0) // Car consumes petrol here 
     { 
      usleep(200000); 
      cout << car->petrol << endl; 
      car->petrol -= 1; 
     } 
     cout << "-----End of fuel-----" << "\t\t #" << i << endl; 

     pthread_mutex_lock(&mutex1); 
     if (petrolDistributor.petrol >= 30) // If distributor almost empty? 
     { 
      petrolDistributor.petrol -= car->capacity; //Substract car's capacity amount of fuel from distributor 
      car->petrol = car->capacity;    //Fillup mentioned capacity in car 
     } 
     else 
     { 
      petrolDistributor.isEmpty = true; 
      pthread_cond_signal(&isempty); 
     } 
     pthread_mutex_unlock(&mutex1); 
    } 
} 

メイン:

int main() 
{  
    pthread_t car; 
    pthread_t supply; 

    Car carPetrol; 

    pthread_cond_init(&isempty, NULL); 
    pthread_mutex_init(&mutex1, NULL); 

    pthread_create(&car, NULL, threadPetrolDriver, (void*) (&carPetrol)); 
    pthread_create(&supply, NULL, threadSupply, NULL); 

    // pthread_join(&car, NULL);  //results error: invalid conversion from ‘pthread_t* {aka long unsigned int*}’ to ‘pthread_t {aka long unsigned int}’ [-fpermissive]| 
    // pthread_join(&supply, NULL); 
    pthread_exit(NULL); 

    return 0; 
} 

出力例:

-----End of fuel----- #0 
9 
(...) 
2 
1 
-----End of fuel----- #1 
-----End of fuel----- #2 //Also for loop increments 
10 
9 
(...) 
3 
2 
1 
-----End of fuel----- #3 
10 
9 
(...) 

、出力はそのように見えない理由の質問はありますか?時には5回の反復がうまくいき、6回目にダブルメッセージが表示されます。そして、参加に間違いはありますか? アドバイスをいただきありがとうございます。

+0

'pthread_cond_t'を初期化する必要性を認識しているようですが、あなたの' pthread_mutex_t'sをデフォルトで初期化したままの内容であるように見えるのは少し不思議です。また、 'pthread_cont_t'がセマフォーであると思われるようです。そうではない。 – EOF

+0

答えを出してくれてありがとう、ミューテックスの初期化がありません。私が他のStackのトピックを尋ねるときに、あなたのアドバイスの2番目の部分をどのように使うのか分かりません。人々は 'pthread_mutex_t'と' pthread_cont_t'をそういう形で混ぜるように勧めましたが、間違っている可能性があります – Macieyo

+1

注:pthread_join() pthread_idですが、あなたはpthread_tを提供しています。同じことではありません。 (これは彼の(主な)質問ではないので、答えではありません。) –

答えて

0

petrolDistributorがほぼ空であることがわかると、燃料補給を行わずにもう一度whileループの周りを回るので、車には「燃料の終わり」が何度も表示されることがあります。

車にがあります。燃料が不足していて燃料補給が不十分なpetrolDistributorが見つかった場合は、条件変数を待ちます。 petrolDistributorが給油されるまでには進まないでください。

pthread_mutex_lock(&mutex1); 
if (petrolDistributor.petrol < 30) // If distributor almost empty? 
    pthread_cond_signal(&isempty); 

// wait for sufficient fuel to be available 
while (petrolDistributor.petrol < car->capacity) 
    pthread_cond_wait(&carwaiting, &mutex1); 

// refuel 
petrolDistributor.petrol -= car->capacity; //Substract car's capacity amount of fuel from distributor 
car->petrol = car->capacity;    //Fillup mentioned capacity in car 
pthread_mutex_unlock(&mutex1); 

私はここに新しいconditiona変数carwaitingを使用しました。 petrolDistributor.isEmptyブール値は不要です。述語はちょうどpetrolDistributor.petrol < 30です。あなたが複数の車を含めて、これを拡張した場合ので、私は、ここにpthread_cond_broadcast()を使用しました

pthread_mutex_lock(&mutex1); 

    // Wait for petrol to drop below low-water-mark 
    while(petrolDistributor.petrol >= 30) 
     pthread_cond_wait(&isempty, &mutex1); 

    usleep(2000000); 
    petrolDistributor.petrol = initialFuel; //Refill petrol and change state 
    pthread_cond_broadcast(&carwaiting); // Wake up any cars waiting for fuel 
    pthread_mutex_unlock(&mutex1); 

注意、より多くの1が待っている可能性がありますより:それは駅を補充した後

petrolDistributorは、待機中の車に合図する必要があります燃料。

あなたpthread_join()呼び出しはちょうど次のようになります。

pthread_join(car, NULL); 
pthread_join(supply, NULL); 

pthread_join()は、引数、ないpthread_t *としてpthread_tかかります)。

関連する問題