1

古典的なピーターソンのアルゴリズムでは、クリティカル セクションに入る前に、flag1 と flag2 の 2 つのフラグとターン変数をチェックします。最初にターンをチェックしてからフラグをチェックすると、これは機能しますか?

4

1 に答える 1

0

はい、最初にチェックしてから、またはの条件内をチェックするturnと機能します。flag[0]flag[1]while()

その理由は、両方の条件が真の場合にのみビジー待機が実行されるためです。

証拠として、私はランダムな切り替えを行う 2 つのプロセスをシミュレートする小さな C プログラムを作成しました。

クリティカル セクションでは、プロセス 0 で次のコードを使用します。

global ^= 0x5555;
global ^= 0x5555;
global++;

そしてこれはプロセス1にあります:

global ^= 0xAAAA;
global ^= 0xAAAA;
global++;

どちらのプロセスも、このセクションをそれぞれ 1000 回実行します。2 つのクリティカル セクション間に競合状態がある場合global、シミュレーション終了時の 2000 とは異なる可能性があります。

コード:

#include <stdio.h>
#include <stdlib.h>
#include <time.h>

typedef enum
{
  InstrNop,
  InstrHalt,
  InstrSetVarNum,
  InstrJumpVarZero,
  InstrJumpVarNonzero,
  InstrJump,
  InstrIncVar,
  InstrDecVar,
  InstrXorVarNum,
} tInstr;

int ExecuteInstruction(unsigned* Vars, const unsigned* Program, unsigned* Position)
{
  switch (Program[*Position])
  {
  default:
  case InstrHalt:
    return 0;

  case InstrNop:
    (*Position)++;
    break;

  case InstrSetVarNum:
    Vars[Program[*Position + 1]] = Program[*Position + 2];
    (*Position) += 3;
    break;

  case InstrXorVarNum:
    Vars[Program[*Position + 1]] ^= Program[*Position + 2];
    (*Position) += 3;
    break;

  case InstrJumpVarZero:
    if (Vars[Program[*Position + 1]] == 0)
      (*Position) = Program[*Position + 2];
    else
      (*Position) += 3;
    break;

  case InstrJumpVarNonzero:
    if (Vars[Program[*Position + 1]] != 0)
      (*Position) = Program[*Position + 2];
    else
      (*Position) += 3;
    break;

  case InstrJump:
    (*Position) = Program[*Position + 1];
    break;

  case InstrIncVar:
    Vars[Program[*Position + 1]]++;
    (*Position) += 2;
    break;

  case InstrDecVar:
    Vars[Program[*Position + 1]]--;
    (*Position) += 2;
    break;
  }

  return 1;
}

typedef enum
{
  VarGlobal,

  VarCnt0,
  VarCnt1,

  VarFlag0,
  VarFlag1,
  VarTurn,

  VarIdxMax
} tVarIdx;

unsigned Vars[VarIdxMax];

#define USE_PETERSON 01
#define SWAP_CHECKS 01

const unsigned Program0[] =
{
  // cnt0 = 1000;
  InstrSetVarNum, VarCnt0, 1000,

// 3:
#if USE_PETERSON
  // flag[0] = 1;
  InstrSetVarNum, VarFlag0, 1,
  // turn = 1;
  InstrSetVarNum, VarTurn, 1,
// 9:
  // while (flag[1] == 1 && turn == 1) {}
#if SWAP_CHECKS
  InstrJumpVarZero, VarTurn, 17,
  InstrJumpVarZero, VarFlag1, 17,
#else
  InstrJumpVarZero, VarFlag1, 17,
  InstrJumpVarZero, VarTurn, 17,
#endif
  InstrJump, 9,
// 17:
#endif

// Critical section starts
  // global ^= 0x5555;
  // global ^= 0x5555;
  // global++;
  InstrXorVarNum, VarGlobal, 0x5555,
  InstrXorVarNum, VarGlobal, 0x5555,
  InstrIncVar, VarGlobal,
// Critical section ends

#if USE_PETERSON
  // flag[0] = 0;
  InstrSetVarNum, VarFlag0, 0,
#endif

  // cnt0--;
  InstrDecVar, VarCnt0,
  // if (cnt0 != 0) goto 3;
  InstrJumpVarNonzero, VarCnt0, 3,

  // end
  InstrHalt
};

const unsigned Program1[] =
{
  // cnt1 = 1000;
  InstrSetVarNum, VarCnt1, 1000,

// 3:
#if USE_PETERSON
  // flag[1] = 1;
  InstrSetVarNum, VarFlag1, 1,
  // turn = 0;
  InstrSetVarNum, VarTurn, 0,
// 9:
  // while (flag[0] == 1 && turn == 0) {}
#if SWAP_CHECKS
  InstrJumpVarNonzero, VarTurn, 17,
  InstrJumpVarZero, VarFlag0, 17,
#else
  InstrJumpVarZero, VarFlag0, 17,
  InstrJumpVarNonzero, VarTurn, 17,
#endif
  InstrJump, 9,
// 17:
#endif

// Critical section starts
  // global ^= 0xAAAA;
  // global ^= 0xAAAA;
  // global++;
  InstrXorVarNum, VarGlobal, 0xAAAA,
  InstrXorVarNum, VarGlobal, 0xAAAA,
  InstrIncVar, VarGlobal,
// Critical section ends

#if USE_PETERSON
  // flag[1] = 0;
  InstrSetVarNum, VarFlag1, 0,
#endif

  // cnt1--;
  InstrDecVar, VarCnt1,
  // if (cnt1 != 0) goto 3;
  InstrJumpVarNonzero, VarCnt1, 3,

  // end
  InstrHalt
};

void Simulate(void)
{
  unsigned pos0 = 0, pos1 = 0;

  while (Program0[pos0] != InstrHalt ||
         Program1[pos1] != InstrHalt)
  {
    int cnt;

    cnt = rand() % 50;
    while (cnt--)
      if (!ExecuteInstruction(Vars, Program0, &pos0))
        break;

    cnt = rand() % 50;
    while (cnt--)
      if (!ExecuteInstruction(Vars, Program1, &pos1))
        break;
  }
}

int main(void)
{
  srand(time(NULL));
  Simulate();
  printf("VarGlobal = %u\n", Vars[VarGlobal]);
  return 0;
}

出力 ( ideone ):

VarGlobal = 2000

ここで、 Wikipediaと同じチェック順序のプログラムをSWAP_CHECKS0: 出力 ( ideone )と定義します。

VarGlobal = 2000

最後に、Peterson のアルゴリズムが無効になっているときに競合状態が発生することを示すためにUSE_PETERSON、0: 出力 ( ideone )として定義します。

VarGlobal = 1610
于 2013-03-22T08:34:00.427 に答える