2014-09-02 3 views
1

Я работаю с микроконтроллером NXP LPC1788, и я разрабатываю многопоточное приложение в C. В части моего приложения я определяю структуру данных с настраиваемым списком. Раньше у меня были проблемы с моей программой из-за одновременного доступа к определенному списку, который, по-видимому, я решил решить, внедряя метод блокировки и метод блокировки для списков, которые потоки могут вызывать перед доступом к самому списку.Атомный тестовый набор для микроконтроллера LPC1788

Я сделал это, добавив «Сема» элемент данных в списке структуры:

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 полагается на версию набора команд Thumb, специфичных для микроконтроллеров Cortex-M3, которые можно найти here или в user manual на стр. 918+.

Просматривая это, я не могу найти ничего похожего на инструкцию по тестированию. Я мог бы просто пропустить это.

В идеале я хотел бы иметь что-то вроде этого:

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

EDIT

На основании ответа Немо, я попытался следующее:

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 

У меня возникли проблемы с воспроизведением параллельных проблем доступа (при условии, что это были проблемы параллелизма, которые у меня были), поэтому я не знаю точно, что это работает.

+1

http://www.doulos.com/knowhow/arm/Hints_and_Tips/Implementing_Semaphores/ –

+1

http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dai0321a/BIHEJCHB ,html –

+0

Спасибо за ссылки, я дам им прочитать. – Tagc

ответ

1

В ARM используется парадигма с привязкой к нагрузке/хранилище для атомных операций. См. this question и Section 39.2.4.8 of the user manual, с которыми вы связались для получения дополнительной информации.

[Update]

на основе 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, но это, безусловно, необходимых для более сложных. Современные процессоры имеют сложные модели памяти.

+0

Спасибо! Прежде чем отметить это как принято, не могли бы вы просто взглянуть на мою реализацию (редактирование в исходном сообщении), чтобы подтвердить, что у меня есть правильная идея. – Tagc

+1

Да, ваш код выглядит нормально ... почти. Вы должны прочитать ссылки @HansPassant, особенно с arm.com ... Вам понадобится инструкция '__DNB()' сразу после получения блокировки, чтобы гарантировать, что ЦП не переупорядочивает любые обращения к памяти через операцию блокировки. (Вероятно, это не проблема для очень простых ядер ARM, но определенно проблема в целом.) – Nemo

Смежные вопросы