Проблема с остановкой потока в Linux

Вопросы программирования на Free Pascal, использования компилятора и утилит.

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

Проблема с остановкой потока в Linux

Сообщение coyot.rush » 10.11.2010 22:02:40

Вот такое исключение получаю при попытке "усыпить" поток
Project X raised exception class "EThread" with message:
'Suspend one thread inside another one is unsupported (because it is unsafe and deadlock prone) by *nix and posix operation systems'


поток объявлен в отдельном модуле так
Код: Выделить всё
unit Simplethread;

{$ifdef FPC}{$mode objfpc}{$h+}{$endif}
interface

uses
  Classes;

type

  TSimpleThread = class(Tthread)
    procedure dummy;
    private
   protected
   procedure Execute; override;
  end;
implementation

uses SysUtils,main...;


Пробою

Код: Выделить всё
unit gvar
....
uses Simplethread...;
....
var
p1:T
....


Код: Выделить всё
program Myprogram;

{$ifdef FPC}{$mode objfpc}{$h+}{$endif}
{$ifdef FPC}
{$ifdef mswindows}{$apptype gui}{$endif}
{$endif}
uses
{$ifdef FPC} {$ifdef linux}cthreads, {$endif} {$endif}
  msegui,mseforms,syncobjs,mseguiglob,main,gvar,Simplethread...;
begin
  p1:= TSimpleThread .Create(False);
  p1.Suspend;


В итоге получаю исключение :?:
PS:fpc 2.4+mseide+msegui2.4

Добавлено спустя 2 часа 23 минуты 5 секунд:
из Classes от Kylix
About Suspend and Resume. POSIX does not support suspending/resuming a thread.
Suspending a thread is considerd dangerous since it is not guaranteed where the
thread would be suspend. It might be holding a lock, mutex or it might be inside
a critical section. In order to simulate it in Linux we've used signals. To
suspend, a thread SIGSTOP is sent and to resume, SIGCONT is sent. Note that this
is Linux only i.e. according to POSIX if a thread receives SIGSTOP then the
entire process is stopped. However Linux doesn't entirely exhibit the POSIX-mandated
behaviour. If and when it fully complies with the POSIX standard then suspend
and resume won't work

Интересна последняя сторка
Вольный перевод Если Linux следовал Posix, то функции Resume, Suspend не будут рабать

Для сравнения Kylix
Код: Выделить всё
procedure TThread.Suspend;
begin
  FSuspended := True;
  CheckThreadError(pthread_kill(FThreadID, SIGSTOP));
end;

procedure TThread.Resume;
begin
  if not FInitialSuspendDone then
  begin
    FInitialSuspendDone := True;
    sem_post(FCreateSuspendedSem);
  end else
    CheckThreadError(pthread_kill(FThreadID, SIGCONT));
  FSuspended := False;
end;


FPC

Код: Выделить всё
procedure TThread.Suspend;
begin
  if FThreadID = GetCurrentThreadID then
    begin
      if not FSuspended and
         (InterLockedExchange(longint(FSuspended),ord(true)) = ord(false)) then
        CurrentTM.SemaphoreWait(FSem)
    end
  else
    begin
      Raise EThread.create('Suspending one thread from inside another one is unsupported (because it is unsafe and deadlock prone) by *nix and posix operating systems');
//      FSuspendedExternal := true;
//      SuspendThread(FHandle);
    end;
end;


procedure TThread.Resume;
begin
  if (not FSuspendedExternal) then
    begin
      if FSuspended and
         (InterLockedExchange(longint(FSuspended),ord(false)) = ord(true)) then
        begin
          WRITE_DEBUG('resuming ',ptruint(self));
          CurrentTM.SemaphorePost(FSem);
        end
    end
  else
    begin
      raise EThread.create('External suspending is not supported under *nix/posix, so trying to resume from from an external suspension should never happen');
//      FSuspendedExternal := false;
//      ResumeThread(FHandle);
    end;
end;   


PS:
Неужели проще использовать RTL от Kylix (особенно под Linux) чем пользоваться не доделанными модулями от fpc :shock:
Аватара пользователя
coyot.rush
постоялец
 
Сообщения: 309
Зарегистрирован: 14.08.2009 08:59:48

Re: Проблема с остановкой потока в Linux

Сообщение Sergei I. Gorelkin » 11.11.2010 10:34:29

Да, остановка потоков не поддерживается (за исключением запуска потока в остановленном состоянии). Это небезопасно потому, что состояние потока в момент остановки неизвестно, а остановка в тот момент, когда поток находится в критической секции, приведет к зависанию всех остальных потоков, пытающихся зайти в ту же секцию. По этой же причине в последних версиях delphi методы suspend и resume объявлены deprecated.
Аватара пользователя
Sergei I. Gorelkin
энтузиаст
 
Сообщения: 1406
Зарегистрирован: 24.07.2005 14:40:41
Откуда: Зеленоград

Re: Проблема с остановкой потока в Linux

Сообщение Alexx2000 » 11.11.2010 11:10:58

Я обходил это следующим образом: сделал чтобы остановка потока происходила из самого потока. Для этого к потоку который требуется останавливать я добавлял флаг, сигнализирующий о том что поток требуется остановить и в Execute проверял его значение, и если оно True то вызывал метод Suspend. Правда критические секции в данном случае у меня не использовались.
Аватара пользователя
Alexx2000
постоялец
 
Сообщения: 489
Зарегистрирован: 25.10.2006 00:22:07
Откуда: Мытищи

Re: Проблема с остановкой потока в Linux

Сообщение coyot.rush » 11.11.2010 22:51:12

По этой же причине в последних версиях delphi методы suspend и resume объявлены deprecated.

Теперь ясно откуда
Suspending one thread from inside another one is unsupported (because it is unsafe and deadlock prone) by *nix and posix operating systems


Я обходил это следующим образом: сделал чтобы остановка потока происходила из самого потока. Для этого к потоку который требуется останавливать я добавлял флаг, сигнализирующий о том что поток требуется остановить и в Execute проверял его значение, и если оно True то вызывал метод Suspend. Правда критические секции в данном случае у меня не использовались.

Так и сделаю.

Только что делать с критическими секциями ?
Аватара пользователя
coyot.rush
постоялец
 
Сообщения: 309
Зарегистрирован: 14.08.2009 08:59:48

Re: Проблема с остановкой потока в Linux

Сообщение Vadim » 12.11.2010 03:56:06

coyot.rush писал(а):Только что делать с критическими секциями ?

Останавливать не немедленно, а после того, как пройдёт тот самый критический момент. :)
Vadim
долгожитель
 
Сообщения: 4112
Зарегистрирован: 05.10.2006 08:52:59
Откуда: Красноярск

Re: Проблема с остановкой потока в Linux

Сообщение Sergei I. Gorelkin » 12.11.2010 10:59:03

Вот классическое "сначала создаем себе проблемы, потом героически их решаем". А что мешает создать событие или семафор, на котором будет ждать поток (в четко заданном месте), и сигналить его извне, когда потоку пора проснуться? Две лишних строчки в программе или что?
Аватара пользователя
Sergei I. Gorelkin
энтузиаст
 
Сообщения: 1406
Зарегистрирован: 24.07.2005 14:40:41
Откуда: Зеленоград

Re: Проблема с остановкой потока в Linux

Сообщение coyot.rush » 12.11.2010 18:42:36

Две лишних строчки в программе или что?

Незнание особенностей реализации методов Suspend/Resume под Linux в FPC :oops:
Был уверен что все аналогично. Под Windows остановка потоков совершенно нормальное явление , по крайней мере в user mode . Отладчик OllyDBg прекрасно это делает.

Sergei I. Gorelkin прокомментируйте сей ман http://www.opennet.ru/man.shtml?topic=pthread_kill&category=3&russian=5
особенно
The pthread_kill() function shall request that a signal be delivered to the specified thread

Я так понимаю команда разработчиков fpc отказалась от этого механизма и-за
Это небезопасно потому, что состояние потока в момент остановки неизвестно, а остановка в тот момент, когда поток находится в критической секции, приведет к зависанию всех остальных потоков, пытающихся зайти в ту же секцию.


Возможно ли что бы Suspend отрабатывал тогда кода поток выйдет из критической секции, имхо все таки это не Ring0 и RealTime и мгновенного отклика ни кто не требует.
Аватара пользователя
coyot.rush
постоялец
 
Сообщения: 309
Зарегистрирован: 14.08.2009 08:59:48

Re: Проблема с остановкой потока в Linux

Сообщение Sergei I. Gorelkin » 12.11.2010 22:00:51

Отладка - это совершенно другая история. Отладчик имеет полную власть над отлаживаемой программой, кроме того, отладчик и отлаживаемая программа - два разных процесса. Т.к. у каждого процесса свои критические секции, то отладчик в принципе не может попасть в критическую секцию отлаживаемой программы.

coyot.rush писал(а):Sergei I. Gorelkin прокомментируйте сей ман http://www.opennet.ru/man.shtml?topic=p ... &russian=5
особенно
The pthread_kill() function shall request that a signal be delivered to the specified thread

Сигнал (в терминологии linux) - это исключение (в терминологии windows). При исключении программа обычно завершается, сделав core dump (в linux), или предложив отправить отчет в M$ (в Windows). Кто придумал, что SIGSTOP вызывает остановку, а SIGCONT- продолжение, и насколько это справедливо для всех линуксов - там не указано. Кроме того, сигналы, кроме SIGKILL, можно блокировать, игнорировать или обрабатывать по-своему.

Кроме того, там же написано: Note that pthread_kill() only causes the signal to be handled in the context of the given thread; the signal action (termination or stopping) affects the process as a whole. Дословно: ptread_kill() вызывает только обработку сигнала в контексте заданного потока; действие сигнала (завершение или остановка) влияет на процесс целиком.

Резюмируя: в линуксе вообще не предусмотрены функции, аналогичные виндовым SuspendThread/ResumeThread. Костыль, примененный в kylix, сработал благодаря очень удачному стечению обстоятельств.

coyot.rush писал(а):Возможно ли что бы Suspend отрабатывал тогда кода поток выйдет из критической секции, имхо все таки это не Ring0 и RealTime и мгновенного отклика ни кто не требует.

Нет.
Аватара пользователя
Sergei I. Gorelkin
энтузиаст
 
Сообщения: 1406
Зарегистрирован: 24.07.2005 14:40:41
Откуда: Зеленоград

Re: Проблема с остановкой потока в Linux

Сообщение coyot.rush » 12.11.2010 22:50:56

http://pauillac.inria.fr/~xleroy/linuxthreads/faq.html
E.4: How can I suspend and resume a thread from another thread? Solaris has the thr_suspend() and thr_resume() functions to do that; why don't you?
The POSIX standard provides no mechanism by which a thread A can suspend the execution of another thread B, without cooperation from B. The only way to implement a suspend/restart mechanism is to have B check periodically some global variable for a suspend request and then suspend itself on a condition variable, which another thread can signal later to restart B.

Notice that thr_suspend() is inherently dangerous and prone to race conditions. For one thing, there is no control on where the target thread stops: it can very well be stopped in the middle of a critical section, while holding mutexes. Also, there is no guarantee on when the target thread will actually stop. For these reasons, you'd be much better off using mutexes and conditions instead. The only situations that really require the ability to suspend a thread are debuggers and some kind of garbage collectors.

Лучше использовать мьютексы :!:

Но

If you really must suspend a thread in LinuxThreads, you can send it a SIGSTOP signal with pthread_kill. Send SIGCONT for restarting it. Beware, this is specific to LinuxThreads and entirely non-portable. Indeed, a truly conforming POSIX threads implementation will stop all threads when one thread receives the SIGSTOP signal! One day, LinuxThreads will implement that behavior, and the non-portable hack with SIGSTOP won't work anymore.


Итого: В Linux предусмотрены функции, аналогичные Windows SuspendThread/ResumeThread, но только в нем и Solaris больше нигде, например в QNX этого нет http://qnx.org.ru/forum/index.php?topic=1374.0;imode

oftopic
Вот что значит "хакерская" ОС стандартом она иногда не подчиняется
PS
сработал благодаря очень удачному стечению обстоятельств.
имхо, костыль под именем совместимость c соляркой
Аватара пользователя
coyot.rush
постоялец
 
Сообщения: 309
Зарегистрирован: 14.08.2009 08:59:48

Re: Проблема с остановкой потока в Linux

Сообщение avi9526 » 15.01.2012 09:09:36

Sergei I. Gorelkin писал(а):Вот классическое "сначала создаем себе проблемы, потом героически их решаем". А что мешает создать событие или семафор, на котором будет ждать поток (в четко заданном месте), и сигналить его извне, когда потоку пора проснуться? Две лишних строчки в программе или что?

Собственно по данному поводу возникла проблема.
Кто-нибудь может объяснить (и/или пример дать) как по человечески в линуксе для thread сделать resume или suspend через события или еще как ?
Спасибо!
Аватара пользователя
avi9526
новенький
 
Сообщения: 16
Зарегистрирован: 25.08.2010 17:10:26


Вернуться в Free Pascal Compiler

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

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

Рейтинг@Mail.ru