2015-11-30 3 views
1

У вас есть два потока, один из которых выполняет функцию f1(), а другой работает f2(). Иногда f1 никогда не заканчивается, несмотря на то, что все отпечатки f2 видны. Объясните, как это может произойти и дать решение?Несколько резьбовых двух нитей достигают одной и той же точки

int _f2_finished = 0; 

Void f1() 
{ 
    print(“f1 waiting “); 
    while (!_f2_finished) {usleep(50);} 
    print(“share of work”); 
} 

void f2() 
{ 
    Printf(“f2 doing some stuff”); 
    usleep(5*1000*1000); 
    Printf(“f2 signaling finished”); 
    _f2_finished = 1; 
    Printf(“f2 signaled finished”); 
} 

Я пытался ее решить, я не мог понять, как прийти f1() остается застрял в петле в то время как, несмотря на все, что сообщения о f2 напечатанного смысла _f2_finished является 1, который выходит из времени цикла?

Это C язык и платформа для окон.

+0

Что библиотеки потоков или потоковой модели вы используете? Что он говорит о доступе к объекту в одном потоке, а другой поток, или, возможно, его модифицирует? –

ответ

2

Большинство моделей нитей указывают, что для доступа к объекту в одном потоке является незаконным, в то время как другой поток может изменить или изменить его. Они предоставляют способы юридически обмениваться данными, такими как атомные операции, мьютексы и т. Д.

Как это бывает, в этом конкретном случае вам нужна гарантия «видимости памяти». То есть что-то, что гарантирует, что изменения, сделанные в одном потоке, будут видны «скоро» в другом потоке. Для обеспечения видимости памяти требуется, чтобы многие оптимизаторы компилятора (такие как кеширование значения переменной в регистре) были отключены, поэтому вы получаете их только при запросе.

В Windows у вас есть много вариантов. Вы можете использовать CRITICAL_SECTION для защиты общего значения или использовать различные операции Interlocked.

На всех известных платформах Windows, используя volatile, чтобы обеспечить видимость памяти в случаях, когда атомарность не нужна, не работает, и маловероятно, что это изменится в ближайшем будущем. Если вы не понимаете этого, проигнорируйте его и просто используйте что-то, что легко получить правильно и трудно ошибиться, как мьютекс. (Потому что, если вы используете таким образом без глубокого понимания, рано или поздно вы будете использовать его в случае, когда это произойдет, чтобы не работать надежно, и ваш код не удастся наихудшим образом в худшее время.)

+0

Я до сих пор не понимаю, почему это незаконно для доступа к объекту, в то время как другой поток изменяет его рано или поздно, значение будет обновлено, а f1 выйдет из цикла while. – Nizarazo

+0

@Nizarazo. Это незаконно, потому что это то, что говорят правила. Нет никакой гарантии, что «рано или поздно значение будет обновлено», потому что нет такой вещи, как «* значение *». Нет «одного истинного значения», потому что правила этого не требуют. Правила просто требуют, чтобы, если ваша программа соответствует правилам, она работает правильно. Они не требуют от компилятора выяснить, как создавать программы, нарушающие работу правил. –

+0

В вашем случае цикл 'while', вероятно, только читает' _f2_finished' один раз. Поскольку правила говорят, что вы не можете изменить его в другом потоке, компилятор может предположить, что его значение не может измениться. Это делает код, который следует правилам более эффективным. Компилятору не требуется выяснять, как сохранить ваши наивные предположения действительными, и, скорее всего, это не так. –

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