2

さまざまな最適化オプションについて、gccとiccの動作を確認したかったのです。Petersonの2スレッドミューテックスアルゴリズムを採用しました。このアルゴリズムは、lockメソッドの行aと行b(コメント内)の実行順序が入れ替わっている場合に失敗する可能性があります。iccまたは-O0フラグを指定したgccでコンパイルすると、正しい結果が得られます。-O3フラグを指定してiccを使用してコンパイルすると、誤った結果が生成されます。-O3フラグを指定したgccでコンパイルしても、何も生成されません。プログラムがハングします。したがって、私の推測では、-O3フラグを使用すると、gccとiccの両方がlockメソッドを最適化し、行aと行bの間に依存関係がないと想定しました。したがって、どちらも間違った結果をもたらしました。このような依存関係はコンパイラーが見つけるのが難しいため、特定のコードブロックの依存関係についてコンパイラーに通知する方法(ivdepなどのプラグマ)があります。これにより、コードの他のセクションで-O3フラグを引き続き使用できます。

ロック方法:

void lock(int me)
{
    int other;
    other = 1-me;
    flag[me] = 1; //Line a
    victim = me;  //Line b
    while(flag[other]==1 && victim == me)
    {
    }
}

行aと行bの実行順序が入れ替わった場合のMUTEX違反の例:

T0 0 sets victim=0
T1 1 sets victim=1
T2 1 sets flag[1]=1
T3 1 checks flag[0]. flag[0] not yet set.
T4 1 enters CS
T5 0 sets flag[0]=1 and checks flag[1]. It is set but victim=1.
T6 0 also enters cs

完全なコード:

#include<stdio.h>
#include<pthread.h>
#include<stdlib.h>
#include<time.h>
#include<stdint.h>
int flag[2];
int victim;
int sharedCounter=0;

void lock(int me)
{
    int other;
    other = 1-me;
    flag[me] = 1;
    victim = me;
    while(flag[other]==1 && victim == me)
    {
    }
}

void unlock(int me)
{
    flag[me]=0;
}

void *peterson(void *ptr)
{
    int tId,i;
    tId = (int ) (intptr_t) ptr;
    for(i=0;i<200;i++)
    {
        lock(tId);
        sharedCounter++;
        printf("%d\t",sharedCounter);
        sleep(1/10);
        unlock(tId);
    }
}

main()
{
    int i;
    for(i=0;i<2;i++)
    {
        flag[i]= 0;
    }
    pthread_t t[2];
    for(i=0;i<2;i++)
    {
        pthread_create(&t[i],NULL,peterson,(void *) (intptr_t) i);
    }

    for(i=0;i<2;i++)
    {
        pthread_join(t[i],NULL);
    }
    printf("shared Counter:%d\n",sharedCounter);
    exit(0);
}
4

1 に答える 1

2

変数を「揮発性」として宣言すると、これらの変数の読み取りまたは書き込みのみの並べ替えが防止されます。

于 2012-07-24T10:18:37.457 に答える