Я написал 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 )