Re[3]: синхронизация потоков
От: wander  
Дата: 29.03.14 15:12
Оценка:
Здравствуйте, tdiff, Вы писали:

T>Если не ошибаюсь, в стандарте ++ его вообще нет, так что каждый компилятор ведёт себя, как захочется.

Ошибаешься.
7.1.6.1/7

volatile is a hint to the implementation to avoid aggressive optimization involving the object
because the value of the object might be changed by means undetectable by an implementation. See 1.9 for
detailed semantics. In general, the semantics of volatile are intended to be the same in C++ as they are
in C.

Re[6]: синхронизация потоков
От: Lazin Россия http://evgeny-lazin.blogspot.com
Дата: 30.03.14 07:21
Оценка:
Здравствуйте, dead0k, Вы писали:

D>Здравствуйте, Lazin, Вы писали:

L>>В boost/shared_ptr/detail есть простой spin_lock, который полностью header-only и построен на атомарных операциях и барьерах.
D>Можно ссылку?
D>Я просто всегда думал, что атомарные операции и барьеры суть std/crt. Т.е. все равно вызов неких библиотечных функций

нет, это либо ассемблерные вставки, либо интринсики компилятора, посмотреть можно в реализации boost/shared_ptr/detail/spin_lock.h
Re: синхронизация потоков
От: imerlin  
Дата: 30.05.14 13:59
Оценка:
Здравствуйте, tdiff, Вы писали:

T>Возьмём классический пример синхронизации потоков:



{...}

T>Подобный код приводится в качестве примера ошибочного, т.к. может быть оптимизирован компилятором до


{...}
T>Такая оптимизация возможна, т.к. компилятор видит, что раз внутри work() flag не меняется, поэтому
T>нет смысла считывать его на каждой итерации.


T>Стандартное в практике решение этой проблемы — использовать mutex:

{...}
T>Моё предположение такое: где-то внутри mutex используется какая-то специальная инструкция типа memory barrier, которую компилятор не может позволить себе отоптимизировать.
T>Так ли это? Если да, то что это за инструкция на самом деле?

Насколько я знаю то что Вы написали в качестве "правильного" варианта тоже неверно. Обычно рекомендуется использовать специальные объекты ядра — события, семафоры, мьютексы (я проглядел по диагонали, по моемы Вы под мьютексом понимаете нечто другое). Когда Вы синхронизируетесь с помощью объекта ядра Ваш ждущий поток не крутится в цикле, поедая драгоценное время, а выключается из планировщика потоков и сразу же ставится в очередь как только объект сигнализирует о том, что ожидание закончилось.

То есть схема такая:
//Вы создаете событие в обоих синхронизируемых процессах.
HANDLE hEv=CreateEvent(NULL,FALSE,TRUE,"lalala");
//затем один процесс "засыпает" до окончания работы второго:
WaitForSingleObject(hEv);
//и делает что то дальше
//**********************************
//второй процесс чтото делает
{...}
//по окончании говорит, что момент пришел:
SetEvent(hEv) //именно в этот момент "проснется", то есть вернется из функции WaitForSingleObject первый процесс.

Компилятор, естественно, там ничего оптимизировать и испортить не сможет.

Извините, если не понял Вашего вопроса.
Re: синхронизация потоков
От: Abyx Россия  
Дата: 03.06.14 10:18
Оценка:
Здравствуйте, tdiff, Вы писали:

T>Возьмём классический пример синхронизации потоков:


T>
T>bool flag = false;
T>void thread_1()
T>{
T>    while (!flag) {
T>        work();
T>    }
T>}

T>void thread_2()
T>{
T>    sleep(1000);
T>    flag = true;
T>}

T>

T>В функции work() flag не меняется.

T>Подобный код приводится в качестве примера ошибочного, т.к. может быть оптимизирован компилятором до

T> ...

Нет. Этот код является ошибочным, потому что тут есть race condition, наличие которого приводит к UB (undefined behavior).
если есть UB, уже не важно что именно сгенерит компилятор.

Какие-то люди писали выше что достаточно написать volatile. Нет. Volatile не убирает race condition, код по прежнему будет приводить к UB.

Race condition возникает когда "a program ... contains two conflicting actions in different threads, at least one of which is not atomic, and neither happens before the other".
"conflicting actions" — это когда одно из действий — запись.
"happens before" — это когда либо действия выполняются в одном потоке, либо в разных но с мьютексом.

По этому правильные решения — это либо использовать атомарный тип (например std::atomic<bool>), либо использовать мьютекс.
In Zen We Trust
Re[2]: синхронизация потоков
От: Lazin Россия http://evgeny-lazin.blogspot.com
Дата: 04.06.14 21:00
Оценка:
A>Нет. Этот код является ошибочным, потому что тут есть race condition, наличие которого приводит к UB (undefined behavior).
A>если есть UB, уже не важно что именно сгенерит компилятор.

A>Какие-то люди писали выше что достаточно написать volatile. Нет. Volatile не убирает race condition, код по прежнему будет приводить к UB.


A>Race condition возникает когда "a program ... contains two conflicting actions in different threads, at least one of which is not atomic, and neither happens before the other".

A>"conflicting actions" — это когда одно из действий — запись.
A>"happens before" — это когда либо действия выполняются в одном потоке, либо в разных но с мьютексом.

A>По этому правильные решения — это либо использовать атомарный тип (например std::atomic<bool>), либо использовать мьютекс.


вопрос же не об этом был
Re[3]: синхронизация потоков
От: Abyx Россия  
Дата: 04.06.14 21:22
Оценка:
Здравствуйте, Lazin, Вы писали:

A>>Нет. Этот код является ошибочным, потому что тут есть race condition, наличие которого приводит к UB (undefined behavior).

A>>если есть UB, уже не важно что именно сгенерит компилятор.

A>>Какие-то люди писали выше что достаточно написать volatile. Нет. Volatile не убирает race condition, код по прежнему будет приводить к UB.


A>>Race condition возникает когда "a program ... contains two conflicting actions in different threads, at least one of which is not atomic, and neither happens before the other".

A>>"conflicting actions" — это когда одно из действий — запись.
A>>"happens before" — это когда либо действия выполняются в одном потоке, либо в разных но с мьютексом.

A>>По этому правильные решения — это либо использовать атомарный тип (например std::atomic<bool>), либо использовать мьютекс.


L> вопрос же не об этом был


это гадания о том, нужен volatile или нет, вместо того чтобы заглянуть в стандарт, и поискать упоминания volatile в [intro.multithread].
In Zen We Trust
Re[4]: синхронизация потоков
От: Lazin Россия http://evgeny-lazin.blogspot.com
Дата: 05.06.14 09:20
Оценка:
A> это гадания о том, нужен volatile или нет, вместо того чтобы заглянуть в стандарт, и поискать упоминания volatile в [intro.multithread].

Начнем с того, что у ТС-а ни слова нет о новом стандарте, поэтому, рассказывать о том, что тут race и UB — неправильно, в старом стандарте нет ни слова о многопоточности и любая многопоточная программа это UB и что дальше? Продолжить можно тем, что ТС-а интересовало то, почему оптимизации компилятора не ломают код, вопрос интересный, может лучше было найти в стандарте что-нибудь об этом? Я может быть резковат, но это потому, что меня уже порядком достали пуристы от стандартизации. Это С++, детка, UB это не всегда плохо
Re[4]: синхронизация потоков
От: smeeld  
Дата: 05.06.14 10:43
Оценка: -1
Здравствуйте, Abyx, Вы писали:


A> это гадания о том, нужен volatile или нет, вместо того чтобы заглянуть в стандарт, и поискать упоминания volatile.


Скажите, мастер, такой код корректен и работоспособен?

В потоках:


std::unique_lock<std::mutex> lck( mt );

do{

  if(!que.empty()) break;
   run=0; 
    cv.wait(lck); run=1;

      }while(1);



В главном, ожидание:
while(i>0){
   
  mp_t& mp=mp_p[--i];
  
  if(mp.run){  i=num_th; usleep(10); continue; };
   break;
  };

 delete [] mp_p;
};
Re[5]: синхронизация потоков
От: Abyx Россия  
Дата: 05.06.14 10:46
Оценка:
Здравствуйте, Lazin, Вы писали:

A>> это гадания о том, нужен volatile или нет, вместо того чтобы заглянуть в стандарт, и поискать упоминания volatile в [intro.multithread].


L>Начнем с того, что у ТС-а ни слова нет о новом стандарте,

новый это С++14 или тот которому уже несколько лет?

L>Я может быть резковат, но это потому, что меня уже порядком достали пуристы от стандартизации. Это С++, детка, UB это не всегда плохо

а меня достали говнокодеры которые пишут говно с UB, которое перестает работать в новых версиях компилятора, или не работает с другими компиляторами.
еще меня достали всякие отсталые, которые живут в нулевых, а то и в 90х.
In Zen We Trust
Re[5]: синхронизация потоков
От: Abyx Россия  
Дата: 05.06.14 10:50
Оценка:
Здравствуйте, smeeld, Вы писали:

S>Скажите, мастер, такой код корректен и работоспособен?

отформатируй так чтоб его читать можно было.
In Zen We Trust
Re[6]: синхронизация потоков
От: Lazin Россия http://evgeny-lazin.blogspot.com
Дата: 05.06.14 11:08
Оценка:
Здравствуйте, Abyx, Вы писали:

L>>Начнем с того, что у ТС-а ни слова нет о новом стандарте,

A>новый это С++14 или тот которому уже несколько лет?

тот, которому несколько лет

L>>Я может быть резковат, но это потому, что меня уже порядком достали пуристы от стандартизации. Это С++, детка, UB это не всегда плохо

A>а меня достали говнокодеры которые пишут говно с UB, которое перестает работать в новых версиях компилятора, или не работает с другими компиляторами.

ну значит код std::atomic писали такие люди, так как там — UB, если например сделать так:

std::atomic<int> x; 
.... 
x.store(0, memory_order_relaxed);


то там в шаблоне переменной просто значение присвоится и все, прямо как у топикстартера в примере, ну то есть по сути, store(value, memory_order_relaxed) — не более чем аннотация для людей, которые это потом будут читать (на x86)
Re[7]: синхронизация потоков
От: dead0k  
Дата: 05.06.14 11:25
Оценка: +1
Здравствуйте, Lazin, Вы писали:

L>то там в шаблоне переменной просто значение присвоится и все, прямо как у топикстартера в примере, ну то есть по сути, store(value, memory_order_relaxed) — не более чем аннотация для людей, которые это потом будут читать (на x86)

Атомарно же? А больше от relaxed, вроде бы, ничего и не требуется
Re[2]: синхронизация потоков
От: wander  
Дата: 05.06.14 12:01
Оценка:
Здравствуйте, Abyx, Вы писали:

A>Какие-то люди писали выше что достаточно написать volatile. Нет. Volatile не убирает race condition, код по прежнему будет приводить к UB.


Сколько тут было ответов и все почему-то подумали, что предлагалось использовать только volatile.
Между тем, предлагалось добавить volatile к решению с мьютексами (volatile bool + mutex).
fdn721, предложил именно добавить volatile в целях запретить оптимизации с bool флагом (именно об этом (об оптимизации) был вопрос), а не заменить на volatile всю синхронизацию.
Re[7]: синхронизация потоков
От: Abyx Россия  
Дата: 05.06.14 13:26
Оценка:
Здравствуйте, Lazin, Вы писали:

L>ну значит код std::atomic писали такие люди, так как там — UB, если например сделать так:


L>
L>std::atomic<int> x; 
L>.... 
L>x.store(0, memory_order_relaxed);
L>


L>то там в шаблоне переменной просто значение присвоится и все, прямо как у топикстартера в примере, ну то есть по сути, store(value, memory_order_relaxed) — не более чем аннотация для людей, которые это потом будут читать (на x86)


:doublefacepalm: прочитай уже [intro.multithread]. Там написано про и про UB и про relaxed.

Я вообще фигею. Люди не читали даже *вводную* часть стандарта, а сидят тут с умными щами и пытаются что-то доказывать.
In Zen We Trust
Re[3]: синхронизация потоков
От: Abyx Россия  
Дата: 05.06.14 13:41
Оценка:
Здравствуйте, wander, Вы писали:

W>Между тем, предлагалось добавить volatile к решению с мьютексами (volatile bool + mutex).

W>fdn721, предложил именно добавить volatile в целях запретить оптимизации с bool флагом (именно об этом (об оптимизации) был вопрос), а не заменить на volatile всю синхронизацию.

volatile не добавляет коду с мьютексами ничего полезного.
In Zen We Trust
Re[8]: синхронизация потоков
От: Lazin Россия http://evgeny-lazin.blogspot.com
Дата: 05.06.14 13:54
Оценка:
A>:doublefacepalm: прочитай уже [intro.multithread]. Там написано про и про UB и про relaxed.
A>Я вообще фигею. Люди не читали даже *вводную* часть стандарта, а сидят тут с умными щами и пытаются что-то доказывать.

Может уже хватит придираться? Я просто намекнул на то, что relaxed семантика это просто обычные загрузки и сохранения, если ты читал стандарт, то должен и сам это знать. Я лично, отношусь к этому как к аннотации для читателя кода, о чем и написал, ну и где здесь faceplam?
Re[4]: синхронизация потоков
От: wander  
Дата: 05.06.14 14:44
Оценка:
Здравствуйте, Abyx, Вы писали:

A>volatile не добавляет коду с мьютексами ничего полезного.


Ну и что? Речь вообще не об этом. А о том, что совет, пусть и не совсем полезный, был воспринят вообще неверно. В другом, так сказать, контексте.
Re[2]: синхронизация потоков
От: HolyNick  
Дата: 20.06.14 13:05
Оценка:
Где Вы здесь усмотрели race condition (результат выполнения зависит от порядка исполнения потоков)? (пока считаем, что никакой оптимизации нет над переменной)
Re: синхронизация потоков
От: HolyNick  
Дата: 20.06.14 13:29
Оценка:
T>void thread_1_sync()
T>{
T> while (true) {
T> {
T> scoped_lock lock(m);
T> if (flag) break;
T> }
T> work();
T> }
T>}

T>void thread_2_sync()

T>{
T> sleep(1000);
T> {
T> scoped_lock lock(m);
T> flag = true;
T> }
T>}
T>[/code]

Мьютексы здесь вообще не нужны.
Re: синхронизация потоков
От: HolyNick  
Дата: 20.06.14 13:45
Оценка:
T>Вопрос: что помешает компилятору и в этом случае оптимизировать чтение значения flag примерно вот так:
T>
T>void thread_1_sync_real()
T>{
T>    bool f;
T>    scoped_lock lock(m) {
T>        f = flag;
T>    }
T>    while (true) {
T>        if (f) break;
T>        work();
T>    }
T>}
T>


Компилятор не будет так жонглировать кодом: из void thread_1_sync() он никак не сделает void thread_1_sync_real()...Разные функции абсолютно у Вас получились.
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.