LINUX.ORG.RU

Вопрос к мультитред-UB-теоретикам

 , ,


0

5

Допустим есть такой код:

flag = 0;
while(!flag) {
  /* ... тут много кода, у компилятора нет шансов его оттрассировать до конца ... */
}
flag - обычный int, не атомик, и даже не volatile

Где-то в другом треде однажды ставится flag = 1 (вокруг этой операции тоже много кода). И всё это без межтредовой синхронизации (точнее, где-то в другом коде она может быть, но сама по себе и с переменной flag явно не связана).

У меня есть подозрение, что формально это некоторые могут посчитать UB, так ли это? Если да, то можете ли привести пример, с любыми дикими опциями оптимизатора и любым плеванием на здравый смысл разработчиков компилятора, но в рамках реальности, при каких условиях подобная логика может сломаться?

Ожидаемое поведение: спустя небольшое время на обработку процового конвеера с операцией записи единицы в flag + выгрузку всех процовых writeback кешей, если они есть + ожидание завершения тела цикла, цикл прекратится.

Поскольку возникло непонимание вопроса, уточняю:

static int flag;
static void * threadfunc(void *p) {
  flag = 0;
  while(!flag) {
    /* много кода */
  }
  return NULL;
}

extern void set_flag_1(void) {
  flag = 1;
}

★★★★★

Последнее исправление: firkax (всего исправлений: 4)
Ответ на: комментарий от rupert

Так же не вижу в ТС посте никаких &flag.

У него там

extern void set_flag_1(void) {
  flag = 1;
}

То есть, имеется функция, которая может взвести флажок, и которую можно вызвать из другой единицы трансляции.

Beewek ★★
()
Ответ на: комментарий от DumLemming

А ну-ка, ржаволожцы, как на вашей любимке такое делается?

Там в компайлтайме запрещено обращение к одной переменной из разных потоков без упаковывания переменной в мьютекс.

khrundel ★★★★
()
Ответ на: комментарий от vbr

Ансейф не освобождает от борроучекера.

Ну, т.е. наверняка есть что-то низкоуровневое, на чем эти механизмы синхронизации сделаны, но это потребует сырых указателей, так что вряд ли этим будет удобно пользоваться.

А так есть данные внутри мутексов, чтоб обращаться из разных потоков, есть каналы, чтоб заполнять структуру в одном потоке и потом отдавать в другой, в остальное время программа работает с данными подразумевая что никто из соседнего потока не вмешается.

khrundel ★★★★
()
Ответ на: комментарий от khrundel

Ну, т.е. наверняка есть что-то низкоуровневое, на чем эти механизмы синхронизации сделаны

В том же Cuda реализовали барьерную синхронизацию (которая дёргает аппаратные механизмы синхронизации) где можно заставить поток ждать синхронизации на разных уровнях: других потоков в варпе, блоке, использования разделяемой или глобальной памяти и тд. Для этого используются отдельные абстракции типа грид, блок и варп. Решение годное, но нужно иногда поломать голову как положить на это обычную логику приложения.

Obezyan
()