(решено)Что такое семафор и куда пропадает один художник?

Форум для изучающих FPC и их учителей.

Модератор: Модераторы

(решено)Что такое семафор и куда пропадает один художник?

Сообщение vitaly_l » 01.04.2018 13:09:25

Вот тут взял код от runewalsh viewtopic.php?f=23&t=27493#p131008
И там же узнал о существовании семафора.

Переделал код вот в такой тест.
Код: Выделить всё
{$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, то пересчитывает с семафором. Если иное то без.
Последний раз редактировалось vitaly_l 01.04.2018 21:59:46, всего редактировалось 1 раз.
Аватара пользователя
vitaly_l
долгожитель
 
Сообщения: 3333
Зарегистрирован: 31.01.2012 16:41:41

Re: Что такое семафор и куда пропадает один художник?

Сообщение stesl » 01.04.2018 17:04:05

Блин, я думал ты прикалываешься с семафором - троллишь.
Если на пальцах, то семафор это такая штука (называя его объектом ядра - ясности не прибавляет, верно?) которая вроде переменной. Если она больше ноля, то поток через нее, а вернее через строчку
WaitForSingleObject(Sem, INFINITE);
пройдёт, но уменьшит значение семафора на 1. Следующий поток уменьшит ещё на единичку. И так пока симафор не станет 0. При 0 никакой поток этот баръер уже не преодолеет.
Соответственно выставляя в нужных местах wait и release ты не даёшь потокам косячить с какой то НАПРИМЕР общей для них переменной. Синхронизируешь потоки.
И таких объектов всего 4, если не ошибаюсь. Еще критическая секция, событие, и... чот забыл :|
Мне в этой карусели художников как то некомфортнее. Эта новая область программирования - про потоки + фишки, которых еще не видел. Я до этого только на классическом, из учебника паскале и мучался - ваял что либо

Добавлено спустя 16 минут 23 секунды:
4 - й объект мьютекс, вспомнил. Если я правильно понял, то это и есть семафор, только он всегда равен 1. Можно спросить, а на кой это надо? Если можно смело реализовывать это через переменные. А вот тут и становится важным определение - объект ядра. То есть все делается на этом уровне. И надежней, да и быстрее, в плане выполнения.
В чем то могу ошибаться. Сам сопляк ещё в этой теме ;)
stesl
новенький
 
Сообщения: 31
Зарегистрирован: 30.03.2018 05:40:02

Re: Что такое семафор и куда пропадает один художник?

Сообщение vitaly_l » 01.04.2018 17:21:28

stesl писал(а):Сам сопляк ещё в этой теме

Будете так самоутверждаться, навсегда им и останетесь.

stesl писал(а):Соответственно выставляя в нужных местах wait и release ты не даёшь потокам косячить с какой то НАПРИМЕР общей для них переменной.

Вот я выставлял их и запрещал им больше одного потока:
Код: Выделить всё
         WaitForSingleObject(Sem, INFINITE);
         inc(iCount);
         ReleaseSemaphore(Sem, 1, nil);

Соответственно, ввиду запрета больше чем 1 поток, счётчик должен был-бы считать правильно. Но inc(iCount); всё равно посчитался ложно.

Возможно семафор для QueueUserWorkItem не работает?


.
Аватара пользователя
vitaly_l
долгожитель
 
Сообщения: 3333
Зарегистрирован: 31.01.2012 16:41:41

Re: Что такое семафор и куда пропадает один художник?

Сообщение runewalsh » 01.04.2018 21:30:10

Код: Выделить всё
if boSemaphore then begin
    WaitForSingleObject(Sem, INFINITE);
    inc(iCount);
    ReleaseSemaphore(Sem, 1, nil);
end;
inc(iCount);

Второй inc(iCount) ничем не защищён...
Аватара пользователя
runewalsh
постоялец
 
Сообщения: 457
Зарегистрирован: 27.04.2010 00:15:25

Re: Что такое семафор и куда пропадает один художник?

Сообщение vitaly_l » 01.04.2018 21:43:14

runewalsh писал(а):Второй inc(iCount) ничем не защищён...

Всё правильно - не защищён, для выключенного boSemaphore .

Но не защищён только когда не работает кусок if boSemaphore then begin.
А когда он включен, то Второй inc(iCount) запускается только после него,
соответственно при включенном boSemaphore счёт должен быть верный. Верно?
Но счёт и при включенном boSemaphore - даёт сбой.

Мне кажется, там что-то другое, непонятное сбивающее работу семафора, т.к. я пробовал семафор в других вариантах (там где нет вложенных потоков, запускаемых из под потока) программа считает всех художников. Соответственно, семафор работает с QueueUserWorkItem (пробовал на громадных числах) .

Но ПРЕДПОЛОЖИТЕЛЬНО, при вложенных потоках, что-то там ломается в семафоре.
Аватара пользователя
vitaly_l
долгожитель
 
Сообщения: 3333
Зарегистрирован: 31.01.2012 16:41:41

Re: Что такое семафор и куда пропадает один художник?

Сообщение runewalsh » 01.04.2018 21:56:32

...
После того, как ты отпустил семафор, его тут же получает право занять другой поток. Два inc(iCount) потенциально помешают друг другу и в итоге один пропустится.
Аватара пользователя
runewalsh
постоялец
 
Сообщения: 457
Зарегистрирован: 27.04.2010 00:15:25

Re: Что такое семафор и куда пропадает один художник?

Сообщение vitaly_l » 01.04.2018 21:58:46

runewalsh писал(а):После того, как ты отпустил семафор, его может тут же

Верю. +100500

Тема закрыта. Теперь, семафор идентифициован. Спасибо.
Аватара пользователя
vitaly_l
долгожитель
 
Сообщения: 3333
Зарегистрирован: 31.01.2012 16:41:41

Re: (решено)Что такое семафор и куда пропадает один художник

Сообщение stesl » 02.04.2018 02:28:06

Вот правильно runewalsh заметил в той самой ветке, откуда код взят. Нет понимания начального - нет толка. И там да, пока что мозаика не сложилась у меня в голове. Наверно потому, что в самом учебном материале нет объяснения от ноля до какого то уровня ни про WinAPI, ни про .NET, предмет - теория о потоках (и конечно не только о них,но - в общем разрезе - сами понятия), а вот с объектами для синхронизации как то зашло. Наверно потому что тут и важна теория.
Смысл такой, что семафор ( и другие объекты) управляют (позволяют синхронизировать) работой потоков. И совершенно не важно откуда пришел поток к семафору, т.е. вызвал его ты, каким то образом чужой код (системный) в твои строки зашел - если семафор равен 0, то поток будет ждать. Кстати, самому понравился пример, правда не знаю насколько он реален - про чужой код. В этом случае, твоя булевая переменная ему может оказаться пох, а вот на семафоре он точно споткнется.

Таким образом, предположение что
vitaly_l писал(а):Возможно семафор для QueueUserWorkItem не работает?

равно как и
vitaly_l писал(а):Но ПРЕДПОЛОЖИТЕЛЬНО, при вложенных потоках, что-то там ломается в семафоре.

в корне не верны. Надеюсь теперь ты это понимаешь.

Убери все свои потоки, и запусти только основной (сам код выполняется в основном потоке) и, в случае начальной инициализации
Код: Выделить всё
Sem := CreateSemaphore(nil, 1, 1, nil);

код отработает от начала до конца. Но поставив вместо первой цифирки 0 - получишь пожизненное зависание. Это начальное "положение" семафора. Вторая цифирка - его максимальное значение.

Ну вроде самоутвердился :D Уровень стал - сопляк++
stesl
новенький
 
Сообщения: 31
Зарегистрирован: 30.03.2018 05:40:02

Re: (решено)Что такое семафор и куда пропадает один художник

Сообщение vitaly_l » 02.04.2018 08:53:20

stesl писал(а):самому понравился пример, правда не знаю насколько он реален - про чужой код. В этом случае, твоя булевая переменная ему может оказаться пох, а вот на семафоре он точно споткнется.

Не "может оказаться пох", а 100% пох. <== И никак иначе.

С другой стороны, художники рады что, Вам (и ещё 1000 чел, тем что молчаливо прочитают) понятно что булева переменная, которая в моём примере - априори не остановит "совпадающие" потоки. http://www.freepascal.ru/forum/viewtopic.php?f=23&t=27493&start=30#p131030

stesl писал(а):Ну вроде самоутвердился Уровень стал - сопляк++

С чем Вас и поздравляем, т.к. Вы просили меня сделать, то, ответ на что знали до своего вопроса и прошения меня написать Вам код.
Однако спасибо за внимание и полезную информацию. В смысле семафор - идентифициован и не требует пере-идентификации.

Соответственно, тема повторно закрыта.
boZadacha := false; :wink:

.
Аватара пользователя
vitaly_l
долгожитель
 
Сообщения: 3333
Зарегистрирован: 31.01.2012 16:41:41


Вернуться в Обучение Free Pascal

Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 6

Рейтинг@Mail.ru