(решено)Что такое семафор и куда пропадает один художник?
 Добавлено: 01.04.2018 13:09:25
Добавлено: 01.04.2018 13:09:25Вот тут взял код от runewalsh viewtopic.php?f=23&t=27493#p131008
И там же узнал о существовании семафора.
Переделал код вот в такой тест.
тест работает, но иногда счётчик художников inc(iCount); врёт всего лишь на единицу, из-за потоков.
Попробовал добавить ReleaseSemaphore. Я не знаю правильно или нет я добавил чёртов семафор, но одного художника по прежнему не могу досчитаться. Точнее он по прежнему куда-то "пропадает" (симафор не работает). Скорее всего я неправильно подключил семафор или семафор вообще не для этого.
Суть понять как мне включить семафор?
Правила: если вводится 1 + enter, то пересчитывает с семафором. Если иное то без.
			И там же узнал о существовании семафора.
Переделал код вот в такой тест.
- Код: Выделить всё
- {$mode objfpc} {$h+} {$codepage UTF8}
 uses
 Windows, SysUtils;
 function QueueUserWorkItem(func: LPTHREAD_START_ROUTINE; Context: pointer; Flags: ULONG): BOOL; stdcall; external kernel32;
 var
 runningTasks: integer; // = 0
 allTasksCompleted: PRTLEvent;
 i,iCount:integer;
 Sem:HANDLE;
 boSemaphore:boolean;
 b:byte;
 label repeattest;
 procedure PrepareTaskQueuing;
 begin
 if InterlockedIncrement(runningTasks) = 1 then RTLEventResetEvent(allTasksCompleted);
 end;
 procedure NoteTaskCompleted;
 begin
 if InterlockedDecrement(runningTasks) = 0 then RTLEventSetEvent(allTasksCompleted);
 end;
 procedure TaskPen(param: pointer); stdcall;
 begin
 if boSemaphore then begin
 WaitForSingleObject(Sem, INFINITE);
 inc(iCount);
 ReleaseSemaphore(Sem, 1, nil);
 end;
 inc(iCount);
 writeln('Художник в потоке №' + IntToStr(GetCurrentThreadID) +
 ' - не знает что такео симафор. Может лучше у программистов спросим? Художники готовят кисточку.');
 //Sleep(random(1));
 writeln('Кисточка готова. Но мы в потоке №' + IntToStr(GetCurrentThreadID) +
 ' - не знаем что такое симафор. Без симафора невозможно нарисовать картину. Что такое симафор?');
 NoteTaskCompleted;
 end;
 procedure TaskColors(param: pointer); stdcall;
 begin
 if boSemaphore then begin
 WaitForSingleObject(Sem, INFINITE);
 inc(iCount);
 ReleaseSemaphore(Sem, 1, nil);
 end;
 inc(iCount);
 writeln('Художник в потоке №' + IntToStr(GetCurrentThreadID) +
 ' - не знает что такео симафор. Художники готовят краски. Для чего мы это делаем?');
 //Sleep(random(1));
 PrepareTaskQueuing;
 writeln('Требование красок (из потока №' + IntToStr(GetCurrentThreadID) + '). Ты знаешь что такое симафор?');
 QueueUserWorkItem(@TaskPen, nil, 0);
 writeln('Краски готовы. Что такое симафор? (поток №' + IntToStr(GetCurrentThreadID) + ')');
 NoteTaskCompleted;
 end;
 procedure TaskArt(param: pointer); stdcall;
 begin
 if boSemaphore then begin
 WaitForSingleObject(Sem, INFINITE);
 inc(iCount);
 ReleaseSemaphore(Sem, 1, nil);
 end;
 inc(iCount);
 writeln('Художник в потоке №' + IntToStr(GetCurrentThreadID) +
 ' - не знает что такео симафор. Художники готовят холст. Зачем мы это делаем?');
 PrepareTaskQueuing;
 writeln('Требование красок (из потока №' + IntToStr(GetCurrentThreadID) + '). Ты знаешь что такое симафор?');
 QueueUserWorkItem(@TaskColors, nil, 0);
 //Sleep(random(1));
 writeln('Холст готов. Что такое симафор? (поток №' + IntToStr(GetCurrentThreadID) + ')');
 NoteTaskCompleted;
 end;
 procedure Tasks(param: pointer); stdcall;
 begin
 if boSemaphore then begin
 WaitForSingleObject(Sem, INFINITE);
 inc(iCount);
 ReleaseSemaphore(Sem, 1, nil);
 end;
 inc(iCount);
 writeln('Попытка выяснить что такое симафор №' + IntToStr(GetCurrentThreadID));
 PrepareTaskQueuing;
 writeln('Вопрос из потока №' + IntToStr(GetCurrentThreadID) + ': Ты знаешь что такое симафор?');
 QueueUserWorkItem(@TaskArt, nil, 0);
 //Sleep(random(1));
 writeln('выполнено (поток №' + IntToStr(GetCurrentThreadID) + ')');
 NoteTaskCompleted;
 end;
 begin
 allTasksCompleted := RTLEventCreate;
 boSemaphore := true; // false
 Sem := CreateSemaphore(nil, 1, 1, nil);
 repeattest:
 for i:=1 to 11111 do begin
 PrepareTaskQueuing;
 writeln('Добавление задачи № '+intToStr(i));
 QueueUserWorkItem(@Tasks, nil, 0);
 end;
 writeln(LineEnding + 'Вопрос задан '+intToStr(iCount)+' художникам. До переезда осталось 666 метров.');
 RTLEventWaitFor(allTasksCompleted);
 if boSemaphore
 then writeln(LineEnding + 'Вопрос задан '+intToStr(iCount)+' художникам, должно быть 88888. До переезда осталось 555 метров.')
 else writeln(LineEnding + 'Вопрос задан '+intToStr(iCount)+' художникам, должно быть 44444. До переезда осталось 555 метров.');
 readln(b);
 iCount := 0;
 if b = 1 then begin
 boSemaphore := true;
 goto repeattest;
 end else begin
 boSemaphore := false;
 goto repeattest;
 end;
 RTLEventDestroy(allTasksCompleted);
 end.
тест работает, но иногда счётчик художников inc(iCount); врёт всего лишь на единицу, из-за потоков.
Попробовал добавить ReleaseSemaphore. Я не знаю правильно или нет я добавил чёртов семафор, но одного художника по прежнему не могу досчитаться. Точнее он по прежнему куда-то "пропадает" (симафор не работает). Скорее всего я неправильно подключил семафор или семафор вообще не для этого.
Суть понять как мне включить семафор?
Правила: если вводится 1 + enter, то пересчитывает с семафором. Если иное то без.
 
 
 Уровень стал - сопляк++
 Уровень стал - сопляк++