Я использую простую программную очередь, основанную на индексе записи и индексе чтения.
Детали введения; Язык: C, Компилятор: GCC Оптимизация: -O3 с дополнительными параметрами, Архитектура: Armv7a, ЦП: Многоядерный, 2 ядра Cortex A-15, Кэш L2: Общий и включенный, Кэш L1: Каждый ЦП включен, Архитектура должна быть кешем последовательный.
ЦП 1 выполняет запись, а ЦП 2 — чтение. Ниже приведен очень упрощенный пример кода. Можно предположить, что начальные значения индексов равны нулю.
ОБЩИЙ:
#define QUE_LEN 4
unsigned int my_que_write_index = 0; //memory
unsigned int my_que_read_index = 0; //memory
struct my_que_struct{
unsigned int param1;
unsigned int param2;
};
struct my_que_struct my_que[QUE_LEN]; //memory
ЦП 1 работает:
void que_writer
{
unsigned int write_index_local;
write_index_local = my_que_write_index; //my_que_write_index is in memory
my_que[write_index_local].param1 = 16; //my_que is my queue and stored in memory also
my_que[write_index_local].param2 = 32;
//similar writing stuff
++write_index_local;
if(write_index_local == QUE_LEN) write_index_local = 0;
my_que_write_index = write_index_local;
}
ЦП 2 работает:
void que_reader()
{
unsigned int read_index_local, param1, param2;
read_index_local = my_que_read_index; //also in memory
while(read_index_local != my_que_write_index)
{
param1 = my_que[read_index_local].param1;
if(param1 == 0) FATAL_ERROR;
param2 = my_que[read_index_local].param2;
//similar reading stuff
my_que[read_index_local].param1 = 0;
++read_index_local;
if(read_index_local == QUE_LEN) read_index_local = 0;
}
my_que_read_index = read_index_local;
}
Хорошо, в обычном случае фатальная ошибка никогда не должна возникать, потому что param1 очереди всегда хранится с постоянным значением 16. Но каким-то образом param1 очереди принимает значение 0, и возникает фатальная ошибка.
Понятно, что это какая-то проблема состояния гонки, но я не могу понять, как это происходит. Индексы обновляются центральными процессорами отдельно.
Я не хочу заполнять свой код барьерами памяти, не понимая суть проблемы. Вы хоть представляете, как это происходит?
Детали: Это система без операционной системы, эти коды отключены от прерываний, и нет вытеснения или переключения задач.
stdatomic.h
. Есть довольно много статей, в том числе фрагменты кода для реализации потокобезопасных буферов; Я настоятельно рекомендую вам сначала внимательно их прочитать. Например: почему код чтения на самом деле должен перечитывать индекс записи, если он не меняется с его точки зрения? - person too honest for this site   schedule 09.10.2015