Intereting Posts
Может ли первый аргумент setpgid () быть лидером сеанса или лидером группы? Как очистить файлы, которые дешифруются во время выполнения, очищаются? Как проверить, находится ли число в диапазоне с помощью Objective-C? nptl SIGCONT и планирование streamов C – самая большая строка из большого Список идентификаторов Vs Список типов параметров в C C, работающая с глобальной переменной Назначение памяти для 3D-массива с использованием тройного указателя У функции вроде макросов нужны обязательные круглые скобки? Я смущен, обратившись к руководству CCC для GCC Как реально реализуются структуры на языке программирования C? В чем разница между char * const и const char *? Почему строки с нулевым завершением? Или: с нулевым завершением против символов + длина хранения C компиляция программы из java-программы параметр формата printf содержит неопределенный escape-символ Почему звездочка в объявлении указателя относится к идентификатору, а не к типу данных?

Потенциал условий гонок в псевдокоде Reader / Writer

Я анализирую следующий псевдокод для условий гонки (немного собственной практики) и смотрю, где это возможно. Псевдокод описывает неопределенный asynchronous считыватель / запись.

Писательская тема

r = 0; w = 1; l = 2; //assign start slot numbers while(1) { write_slot(w); l = w; //last written slot is ww = not(r,l) //assigns next slot so that w is neither r or l } 

Читающая тема

 while(1) { r = l; //read from latest write read(r); } 

Возможности коррупции / условия гонки, которые я нашел до сих пор, – это если переменные, читающие / записывающие, не являются атомарными, и, например, писатель может изменить значение l пока читатель находится на полпути через его чтение (может привести к бессмысленное значение r через разрывное чтение / запись). Есть ли какие-либо условия гонки, которые могут потенциально привести к тому, что читатель и писатель попытаются получить доступ к одному слоту?

Основная проблема заключается в том, что даже назначение переменных не является атомной операцией. Трудность заключается в том, как ваш псевдокод будет выполняться на аппаратном уровне. Большинство компьютеров используют архитектуру «загрузка / хранение», в которой значения из памяти должны быть перемещены в регистр перед перемещением в другое место памяти (т.е. нет прямых операций с памятью для памяти). Это вводит промежуточное состояние (регистр), которое могло бы смешивать вещи в многопоточной ситуации, такой как это.

Я предполагаю, что вы будете использовать r , w и l как переменные в памяти , которые будут видны для обоих streamов. Глобалы и память кучи разделяются между streamами одного и того же процесса, поэтому эта часть проста. Тем не менее, streamи должны иметь свой собственный стек и регистровые состояния, иначе они просто не сработают.

Назначение, такое как строка читателя r = l; сначала загрузит значение из некоторого места памяти (где бы он ни был сохранен) в регистр, а затем сохраните это значение в памяти (где бы он ни хранился). Таким образом, назначение r = l будет чем-то вроде «псевдо-сборки»:

  load r1,addr(l) ; load l from memory into register r1 store addr(r),r1 ; store register r1 to wherever r is kept 

где r1 – некоторый регистр, addr(l) – адрес памяти, где хранится l , а addr(r) – адрес r .

Проблема в вашем случае состоит в том, что регистр одного streamа (скажем, читателя) может сохранять промежуточное значение, а другой stream (писатель) изменяет память. Первый stream (считыватель) будет перезаписывать эту память при сохранении из регистра в память.

Рассмотрим следующую последовательность событий. Обозначения [writer] и [reader] определяют, какой stream выполняет что. Назначение читателя r = l задается как приведенные выше операции сборки, для которых писатель выполняет неприятные операции между ними:

  [writer] r=0; w=1; l=2; // (given starting conditions) [writer] write_slot(w) // w==1 [reader] load r1,addr(l) // load l (value 2) into register r1 [writer] l = w; // l gets w, which is 1 [writer] w = not(r,l) // since r *in memory* is still 0, // and l in memory is 1, // this picks 2 for w. [reader] store addr(r),r1 // stores 2 to r *in memory* [reader] read(r) // read(2) since r==2 [writer] write_slot(w) // write(2) since w==2 

Затем две последние операции могут выполняться параллельно и поэтому они будут пытаться получить доступ к одному слоту одновременно. Поэтому ответ на ваш вопрос – да, это может произойти.

Одним из способов исправить что-то вроде этого является принудительное взаимное исключение : обеспечение того, чтобы некоторый сегмент кода был непрерывным, заставляя другие streamи ждать. Существуют специальные аппаратные инструкции (например, «сравнить и обменивать» CMPXCHG ) и функции операционной системы (например, приостановление выполнения streamов), используемые для реализации взаимного исключения. Как правило, вы должны использовать некоторую библиотеку для синхронизации, и не пытайтесь писать свою собственную технику. Например, см. Pthread_mutex_lock () и pthread_mutex_unlock () библиотеки streamов POSIX для C.