1

NXP LPC1788 マイクロコントローラーを使用しており、C でマルチスレッド アプリケーションを開発しています。アプリケーションの一部で、カスタム リンク リスト データ構造を定義しています。特定のリストへの同時アクセスが原因で、以前はプログラムに問題がありましたが、リスト自体にアクセスする前にスレッドが呼び出すことができるリストの「ロック取得」メソッドと「ロック解放」メソッドを実装することで解決したようです。

リスト構造体に「sema」データメンバーを追加することでこれを行いました:

typedef struct linked_list
{
  list_node_t *head;
  list_node_t *tail;
  uint32_t len;
  NODE_ITEM_TYPE_T itemType;
  uint32_t itemSize;
  uint8_t sema;
} linked_list_t;

私の「ロック取得」方法を以下に示します。

void LIST_AcquireLock(linked_list_t *list)
{
  while(list->sema);
  list->sema = 1;
}

私の「ロック解除」方法を以下に示します。

void LIST_ReleaseLock(linked_list_t *list)
{
  list->sema = 0;
}

私のアプリケーションでは、このように 1 秒間に何千回もアイテムをリストに追加および削除する必要があり、それ以来、同時アクセスに関連するバグに気付いていないため、通常、これは問題なく動作するようです。

ただし、これが機能することをより確実にするために、テストと設定のアプローチを実装する方法があるかどうか疑問に思っていました. LPC1788 は、Cortex-M3 マイクロコントローラに固有の Thumb 命令セットのバージョンに依存しています。これは、こちらまたはユーザー マニュアルの918 ページ以降にあります。

しかし、調べてみると、テスト・アンド・セット命令のようなものは見つかりません。見過ごしてるだけかも。

理想的には、次のようなものが欲しいです。

void LIST_AcquireLock(linked_list_t *list)
{
  do{
    while(list->sema);
  } while(TestAndSet(list->sema));
}

編集

Nemoの回答に基づいて、次のことを試みました。

void LIST_AcquireLock(linked_list_t *list)
{
  // Wait until lock seems free.
  while(list->sema);

  // Make sure lock is actually free.
  do {

    // If the semaphore is locked, we continue.
    // OTHERWISE we try to lock it ourselves.
    if(__LDREXB(&(list->sema))) continue;

    // If __STREXB returns 1, then another thread might have accessed that
    // memory location and we can't be sure the lock operation is atomic,
    // so try the locking procedure again.
  } while(__STREXB(1, &(list->sema)));
}

参考になれば、これは対応するアセンブリ コードです。

LIST_AcquireLock:
??LIST_AcquireLock_0:
       0x56de: 0x7d01         LDRB      R1, [R0, #0x14]
       0x56e0: 0x2900         CMP       R1, #0
       0x56e2: 0xd1fc         BNE.N     ??LIST_AcquireLock_0    ; 0x56de
??LIST_AcquireLock_1:
       0x56e4: 0xf110 0x0114  ADDS.W    R1, R0, #20             ; 0x14
       0x56e8: 0xe8d1 0x1f4f  LDREXB    R1, [R1]
       0x56ec: 0xb2c9         UXTB      R1, R1
       0x56ee: 0x2900         CMP       R1, #0
??LIST_AcquireLock_2:
       0x56f0: 0xf110 0x0114  ADDS.W    R1, R0, #20             ; 0x14
       0x56f4: 0x2201         MOVS      R2, #1
       0x56f6: 0xe8c1 0x2f43  STREXB    R3, R2, [R1]
       0x56fa: 0x2b00         CMP       R3, #0
       0x56fc: 0xd1f2         BNE.N     ??LIST_AcquireLock_1    ; 0x56e4
       0x56fe: 0x4770         BX        LR

同時アクセスの問題を再現するのに問題があるため (同時実行の問題であると仮定して)、これが機能するかどうかはわかりません。

4

1 に答える 1