2016-03-27 17 views
3

私はマルチスレッドでC++でのPetersonのアルゴリズムの簡単な実装を書いています。このプログラムは、2つのスレッドを通して文字列を変更します。しかし、私は最終結果を得ていません。どこが間違っていますか?以前C++ 11 C++にはスレッドモデルがなかったに C++マルチスレッドでのPetersonのアルゴリズム

using namespace std; 

int flag[2]={0,1}; 
int turn; 

void* first(void* data){ 
    flag[0]=1; 
    turn=1; 
    while(flag[1] && turn==1){} 
    string &str=*(static_cast<string*>(data)); 
    if(str!=""){ 
     if(str=="abcd"){ 
      str="Hello"; 
     } 
    } 
    flag[0]=0; 
    pthread_exit(NULL); 
} 

void* second(void* data){ 
    flag[1]=1; 
    turn=0; 
    while(flag[0] && turn==0){} 
    string &str=*(static_cast<string*>(data)); 
    if(str!=""){ 
     if(str=="wxyz"){ 
      str="abcd"; 
     } 
    } 
    flag[1]=0; 
    pthread_exit(NULL); 
} 

int main(){ 
    int rc=0; 
    string s = "wxyz"; 
    pthread_t t; 

    rc=pthread_create(&t,NULL,first,static_cast<void*>(&s)); 
    if(rc!=0){ 
     cout<<"error!"; 
     exit(rc); 
    } 
    rc=pthread_create(&t,NULL,second,static_cast<void*>(&s)); 
    if(rc!=0){ 
     cout<<"error!"; 
     exit(rc); 
    } 

    while(flag[0] && flag[1]!=0){} 
    cout<<s; 

    pthread_exit(NULL); 
    return 0; 
} 

答えて

0

tfirstであり、usecondであり、mainはスレッドが終了するまでpthread_joinで待機する。これにより、mainスピンの必要性が排除されました。

変更:彼らは命令の実行順序を保証などの機能で

pthread_t t,u; 
pthread_create(&t,NULL,first,static_cast<void*>(&s)); 
pthread_create(&u,NULL,second,static_cast<void*>(&s)); 
pthread_join(u,NULL); 
pthread_join(t,NULL); 
//while(flag[0] && flag[1]!=0){} 
cout<<s; 

原子フェンスが残りました。

OUTPUT 
abcd 

Hello 

そしてfirstpthread_createsecondの順序を変更すると、常にHelloに出力しますが、それが第二のスレッドが完了するのを待っている最初のスレッドの非常にアイデアを殺す

。だから、私は上記の変更がそれに対する答えになると思う。

1

。 C++ 11以降、コードは競合条件を引き起こす同じ変数への順序付けられていないアクセスを行います。

競合条件の結果、未定義の動作が発生します。

std::stringを変更すると、アトミックではありません。他のスレッドが読み書きしている間は、安全に実行することはできません。

stdのスレッドプリミティブは、上記の生のpthreadコードより優れたアイデアです。エミュレートできない非常に珍しい機能は除きます。

+0

これで 'std :: thread()'コードがこれより優れているでしょうか? – Adnan

+2

@Adnanはい、また、 'flag'と' turn'std :: atomic型を作成する必要があります。また、文字列へのアクセスをmutexと同期させる必要があります。これをしないと、一方のスレッドは他方のスレッドが正しい順序で(またはまったく)変更を「参照」しません。 –

+0

私は既に、文字列アクセスを相互に排除するPetersonのアルゴリズムを含んでいましたが、 'flag'と' turn'をアトミックにしませんでした。また、文字列の代入をアトミックに変換して(可能な場合)、結果を投稿します。 – Adnan

0

アトミックをリファクタリングします。明示的フェンスに注意して、スレッド間の(非アトミック)文字列への正しい順序付けまたは読み書きを保証してください。

多分、誰かが私の論理を健全性チェックしたいのですか?

#include <iostream> 
#include <thread> 
#include <atomic> 
#include <memory> 

using namespace std; 

// atomic types require the compiler to issue appropriate 
// store-release/load-acquire ordering 
std::atomic<int> flag[2]={{0},{1}}; 
std::atomic<int> turn; 


void first(std::string& str){ 
    flag[0]=1; 
    turn=1; 
    while(flag[1] && turn==1){} 
    std::atomic_signal_fence(std::memory_order_acquire); 
    if(str!=""){ 
     if(str=="abcd"){ 
      str="Hello"; 
      std::atomic_signal_fence(std::memory_order_release); 
     } 
    } 
    flag[0]=0; 
} 

void second(std::string& str){ 
    flag[1]=1; 
    turn=0; 
    while(flag[0] && turn==0){} 
    std::atomic_signal_fence(std::memory_order_acquire); 
    if(str!=""){ 
     if(str=="wxyz"){ 
      str="abcd"; 
      std::atomic_signal_fence(std::memory_order_release); 
     } 
    } 
    flag[1]=0; 
} 

int main(){ 
    string s = "wxyz"; 

    auto t1 = std::thread(first, std::ref(s)); 
    auto t2 = std::thread(second, std::ref(s)); 

    for(; flag[0] && flag[1];) 
     ; 

    std::atomic_signal_fence(std::memory_order_acquire); 
    cout << s << endl; 

    t1.join(); 
    t2.join(); 
    return 0; 
} 

予想される出力:

wxyz 

文末:

現代のメモリ・アーキテクチャは、このアルゴリズムが発明されたとき、彼らが何であったかではありません。現代のチップでは、読んだりメモリに書き込んだりすることはありません。まったく起こりません。

は、次の3時間の予定をキャンセルして、件名にこの素晴らしい話を見て:

私はスレッドが firstが終了したスレッドまで待たなければならなかったので、私は別のスレッドを作成し

https://channel9.msdn.com/Shows/Going+Deep/Cpp-and-Beyond-2012-Herb-Sutter-atomic-Weapons-1-of-2

+0

アトミック 'flag'宣言で' = '記号を削除します。試して、 'abcd'と' wxyz'として出力しました。メモリフェンシングでさえ、望ましい結果を生み出すことはできません。私はそれに来るためにいくつかの提案をしましょう、おそらくフェンシングのいくつかの修正 – Adnan

+0

'' abcd "'が合理的に期待される結果ではない理由を理解できません。メインスレッドと同期していない部分がありますか?いずれのスレッドも起動しなければ、メインスレッドは印刷できますか?いずれかのスレッドが単独で起動すると、競合することなく進行することができます。 – Yakk

+0

@Yakkどちらのフラグもtrueの間、メインスレッドは回転します。 –

関連する問題