2016-10-29 8 views
0

私は1人のエレベーターと1人の人がそれぞれ独自のスレッドとエレベーターを持つようにシミュレートするマルチスレッドプログラムを作成中です。私は最初の段階にあり、作成されたスレッドを取得し、正常に動作することを確認しようとしています。forループを使用して多数のスレッドを作成するときの奇妙な動作

私はforループで初期化しようとしているperson_threadsというpthreadの配列を持っています。ループ内でスレッド番号のメッセージを送信してスレッド内に出力しています。何らかの理由で私は奇妙な振る舞いをしています。forループがいくつかのスレッドを作成する前に適切に反復していないのとほぼ同じです(ループと出力を参照)。この動作はランダムであり、実行ごとにさまざまです。スレッドを正しく作成するためには何が必要なのかよくわかりません。この問題を引き起こしている可能性のあることについて洞察があれば、助けてください。複数の7S、15S、12S、48Sとがあるか

コード

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

#define MAX_PERSONS 49 

void *person(void *myvar); 
void *elevator(void *myvar); 

int main(int argc, char *argv[]){ 

    pthread_t elevator_thread; 
    pthread_t person_threads[MAX_PERSONS]; //My array of threads 

    char *elev_msg = "Elevator thread started"; 

    pthread_create(&elevator_thread, NULL, elevator, (void *) elev_msg); 

    //Here is where I try to initialize messages and threads, 
    //see Persons function and output  

    for (int i = 0; i < MAX_PERSONS; i++){ 
     char msg[50]; 
     snprintf(msg, sizeof msg, "Person thread %d started", i); 
     pthread_create(&person_threads[i], NULL, person, (void *) msg); 
    } 

    printf("Main function after pthread_creates\n"); 

    pthread_join(elevator_thread, NULL); 
    for (int i = 0; i < MAX_PERSONS; i++){ 
     pthread_join(person_threads[i], NULL); 
    } 

    return 0; 
} 

void *person(void *myvar){ 
    char *msg; 
    msg = (char *) myvar; 

    printf("%s\n", msg); 

    return NULL; 
} 

void *elevator(void *myvar){ 
    char *msg; 
    msg = (char *) myvar; 

    printf("%s\n", msg); 

    return NULL; 
} 

出力

[email protected]:~/Documents/OS-Project2$ ./elevator 
Elevator thread started 
Person thread 7 started 
Person thread 7 started 
Person thread 7 started 
Person thread 7 started 
Person thread 7 started 
Person thread 7 started 
Person thread 7 started 
Person thread 8 started 
Person thread 9 started 
Person thread 10 started 
Person thread 12 started 
Person thread 12 started 
Person thread 14 started 
Person thread 15 started 
Person thread 15 started 
Person thread 16 started 
Person thread 17 started 
Person thread 18 started 
Person thread 19 started 
Person thread 20 started 
Person thread 21 started 
Person thread 22 started 
Person thread 23 started 
Person thread 24 started 
Person thread 25 started 
Person thread 26 started 
Person thread 27 started 
Person thread 28 started 
Person thread 29 started 
Person thread 30 started 
Person thread 31 started 
Person thread 32 started 
Person thread 33 started 
Person thread 34 started 
Person thread 35 started 
Person thread 36 started 
Person thread 37 started 
Person thread 38 started 
Person thread 39 started 
Person thread 40 started 
Person thread 41 started 
Person thread 42 started 
Person thread 43 started 
Person thread 44 started 
Person thread 45 started 
Person thread 46 started 
Person thread 47 started 
Person thread 48 started 
Main function after pthread_creates 
Person thread 48 started 

注意してください。この動作は、実行ごとにランダムです。私はそれが実際には常に50スレッドを作成することに気づいたが、私は配列を正しく初期化する必要があります。どんな助けもありがとう。ここで

答えて

2

が原因である:

for (int i = 0; i < MAX_PERSONS; i++){ 
    char msg[50]; 
    snprintf(msg, sizeof msg, "Person thread %d started", i); 
    pthread_create(&person_threads[i], NULL, person, (void *) msg); 
} 

msgパラメータは、ブロックの範囲内でメインスレッドで有効です。ヒープ上にmsgバッファを割り当てて、子スレッドで解放する必要があります。

1

あなたの間違いはここにある:

for (int i = 0; i < MAX_PERSONS; i++){ 
    char msg[50]; 

あなたは、バッファがスタック上に作成された後、破棄取得していることをループの各反復で、メッセージバッファのローカル変数を使用しているので。そして、次の反復で同じメモリを再利用して上書きする可能性があります。

mallocを各スレッドに動的に割り当てる必要があります。これらのスレッドはすべて、共有されず上書きされる独自のメッセージバッファを持っています。

+0

I'LL @alkを編集を終了しますが、意図的に 'msg'宣言を太字にしています。テキストをコードとしてマークすると太字にすることはできないようですので、インデントしません。 –

+0

私はこれをあなたの意図ではないと思いました。だから私の変更を元に戻してください。あるいは、この行にCのコメントを追加するだけですか? – alk

0

他にも述べたように、msgのループは、ループが開始される(または終了する)瞬間に割り当てが解除されます。

ヒープ上に割り当てるほかに、あなただけの、このような「文字列」の配列定義することができます。

int main(int argc, char *argv[]){ 

    pthread_t elevator_thread; 
    pthread_t person_threads[MAX_PERSONS]; //My array of threads 
    char msg[MAX_MSG_LEN + 1][MAX_PERSONS]; 
    char *elev_msg = "Elevator thread started"; 

    pthread_create(&elevator_thread, NULL, elevator, (void *) elev_msg); 

    for (size_t i = 0; i < MAX_PERSONS; i++){ 
    snprintf(msg[i], sizeof msg, "Person thread %zu started", i); 
    pthread_create(&person_threads[i], NULL, person, msg[i]); 
    } 

    ... 

またはより良い一緒に属するものを一緒に持って来る:

struct Person_Thread 
{ 
    pthread_t thread; 
    char msg[MAX_MSG_LEN + 1]; 
}; 

int main(int argc, char *argv[]){ 

    pthread_t elevator_thread; 
    struct Person_Thread person_threads[MAX_PERSONS]; //My array of threads 
    char *elev_msg = "Elevator thread started"; 

    pthread_create(&elevator_thread, NULL, elevator, (void *) elev_msg); 

    for (size_t i = 0; i < MAX_PERSONS; i++){ 
    snprintf(person_threads[i].msg, sizeof person_threads[i].msg, 
     "Person thread %zu started", i); 

    pthread_create(&person_threads[i].thread, NULL, person, 
     person_threads[i].msg]); 
    } 

    ... 
+0

こんにちは@alk、必ずしもmsgメモリが解放されているとは限りません。いくつかのコンパイラはchar msg [50]をループ外に持ち上げるでしょう。これは完全に受け入れられる最適化です。最良の修正は、実際には、バッファの代わりにループ変数を渡して、ローカル記憶域を持つスレッド内に出力するメッセージを作成することです。 –

+0

@EdBayiates:OK、「割り当て解除」は、おそらく実際には*なぜ*変数*のメモリが**無効な***になっているのかという点に多少の違いがあります。各繰り返しで左に(そして再入力)。 – alk

関連する問題