c - LPC1788微 Controller 的原子测试和设置

标签 c arm microcontroller thumb lpc

我正在使用 NXP LPC1788 微 Controller ,并且正在使用 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;
}

通常这似乎工作正常,因为我的应用程序每秒向列表添加和删除项目数千次,从那以后我没有注意到与并发访问相关的任何错误。

但是,为了更加确信这是有效的,我想知道是否有任何方法可以实现测试和设置方法。 LPC1788 依赖于特定于 Cortex-M3 微 Controller 的 Thumb 指令集版本,可在 here 中找到。或在 user manual第 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

我无法重现并发访问问题(假设这是我遇到的并发问题),所以我不确定这是否有效。

最佳答案

ARM 使用“加载链接/存储独占”范例进行原子操作。参见 this questionSection 39.2.4.8 of the user manual您已链接以获取详细信息。

[更新]

基于 the code in the link @HansPassant 提供,我会建议对您的例程进行一些细微的更改:

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

  // 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)));

  // Ensure CPU does not reorder any memory accesses across lock acquisition.
  __DMB();
}

__DMB() 可能与非常简单的 ARM 内核无关,但在更复杂的内核上肯定需要它。现代 CPU 具有复杂的内存模型。

关于c - LPC1788微 Controller 的原子测试和设置,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25626235/

相关文章:

microcontroller - 无法在 openOCD 中启用 STLink

c - 8051F312微 Controller

c - strcpy 如何在幕后工作?

使用 ARM/C 复制字符串

c - 在 ARM Neon 汇编中使用 C 变量

c++ - 在 C++ 中将对象序列化为字节数组

MySQL用户密码问题

c - 在 C 中使用带有非选项参数的 getopt

c - 为什么我的多线程程序有时会阻塞?

java - ARM架构上如何解决 'Maven cannot resolve dependencies'?