Является ли вход в критическую секцию Windows операцией атома c? - PullRequest
0 голосов
/ 13 марта 2020

Я написал FFI для критических секций и написал тест для него в Haxe.

Тесты выполняются в определенном порядке (public function s - это тесты)

Этот тест test_critical_section будет периодически зависать и давать сбой:

1   var criticalSection:CriticalSection;
2
3   #if master
4   public function test_init_critical_section() {
5       return assert(attempt({
6           criticalSection = synch.SynchLib.critical_section_init(SPIN_COUNT);
7           trace('criticalSection: $criticalSection');
8       }));
9   }
10  var criticalValue = 0;
11  var done = 0;
12  var numThreads = 50;
13  function work_in_critical_section(ID:Int, a:AssertionBuffer) {
14      sys.thread.Thread.create(() -> {
15          inline function threadMsg(msg:String)
16              trace('Thread ID $ID: $msg');
17          
18          
19          threadMsg("Attempting to enter critical section");
20          criticalSection.critical_section_enter();
21          threadMsg("Entering crtiical section. Doing work.");
22          Sys.sleep(Std.random(100)/500); // simulate work in section
23          criticalValue+= 10;
24          done++;
25          a.assert(criticalValue == done * 10);
26          threadMsg("Leaving critical section. Work done. done: " + done);
27          criticalSection.critical_section_leave();
28          if (done == numThreads) {
29              a.assert(criticalValue == numThreads * 10);
30              a.done();
31              
32          }
33      });
34  }
35  @:timeout(30000)
36  public function test_critical_section() {
37      var a = new AssertionBuffer();
38      for (i in 0...numThreads)
39          work_in_critical_section(i, a);
40      return a;
41  }

Но когда я добавляю Sys.sleep(ID/5); непосредственно перед входом в критическую секцию (в пустой строке 18), тест проходит каждый раз (с любым количеством потоков) ). Без этого тест проваливается случайным образом (чаще с большим количеством потоков).

Мой вывод из этого теста состоит в том, что вход в критическую секцию не атомарный c, и одновременно пытаются пытаться войти несколько потоков. может оставить критический раздел в неопределенном состоянии (приводя к неопределенному / зависающему поведению).

Это правильный вывод или я просто неправильно использую критические разделы (и, следовательно, тест необходимо переписать )? И если это правильный вывод ... не значит ли это, что для входа в критическую секцию нужен собственный механизм блокировки / синхронизации atomi c? (и далее, если это так ... в чем смысл критических секций, почему бы мне просто не использовать какой-либо механизм синхронизации atomi c?)

Мне это кажется проблематичным c Например, рассмотрим 10 потоков, встречающихся на барьере синхронизации (с пропускной способностью 10), а затем все 10 должны пройти критическую секцию сразу после прибытия 10-го потока, означает ли это, что мне придется синхронизировать / сериализовать доступ к методу входа в критическую секцию (например, с помощью сна, чтобы гарантировать, что только один поток пытается войти в секцию при данном тике, как это сделано для исправления неудачного теста, описанного выше)?

FFI записывается ontop of synchapi.h (см. EnterCriticalSection )

1 Ответ

3 голосов
/ 13 марта 2020

Вы прочитали done за пределами критического раздела. Это состояние гонки. Если вы хотите посмотреть значение done, вам нужно сделать это перед тем, как leave критический раздел.

Вы можете увидеть запись в done из другого потока, вызвав assert перед тем, как запись в criticalValue будет видна потоку, который видел запись в done.

Если критическая секция защищает criticalValue и done, то это ошибка для доступа к любому из они не находятся в критическом разделе, если вы не уверены, что каждый поток, который может получить к ним доступ, завершен. Ваш код нарушает это правило.

...