Многопоточные приложения и связанное с ними в Linux, MacOS
Модератор: Модераторы
-
SovNarKom
- постоялец
- Сообщения: 389
- Зарегистрирован: 28.05.2005 10:37:39
- Откуда: Воронеж [vrn] [36]
- Контактная информация:
Многопоточные приложения и связанное с ними в Linux, MacOS
Народ, а просвятите, как в Linux и MacOS обстоят дела с аналогами
CreateEvent;
WaitForSingleObject;
и т.д. из WinAPI.
Может RTL что нибудь реализовано, кроме критических секций и потоков?
Можно конечно запускать отдельный поток, ждать его завершения и т.д. Но вдруг есть более правильный вариант?
Где можно почитать по сабжу? (можно на C)
Зараенее спасибо.
CreateEvent;
WaitForSingleObject;
и т.д. из WinAPI.
Может RTL что нибудь реализовано, кроме критических секций и потоков?
Можно конечно запускать отдельный поток, ждать его завершения и т.д. Но вдруг есть более правильный вариант?
Где можно почитать по сабжу? (можно на C)
Зараенее спасибо.
- Sergei I. Gorelkin
- энтузиаст
- Сообщения: 1409
- Зарегистрирован: 24.07.2005 14:40:41
- Откуда: Зеленоград
- Контактная информация:
Хорошая статья в тему здесь:
http://www.ibm.com/developerworks/libra ... S_CMP=MGST
А вообще, события (events) вроде бы в RTL реализованы. Или по крайней мере имеются настойчивые попытки их реализации.
http://www.ibm.com/developerworks/libra ... S_CMP=MGST
А вообще, события (events) вроде бы в RTL реализованы. Или по крайней мере имеются настойчивые попытки их реализации.
Re: Многопоточные приложения и связанное с ними в Linux, Mac
Так и не ясно, в каком модуле смотреть events?
p.s. Немного раздражает, что документации по лазарю как кот наплакал
Дополнение(оставляю для потомков
)
Есть модуль syncobjs (благо еще и идет комплектом)
Вместо СreateEvent() идет TEvent.Create();
Вместо WaitForSingleObject соответственно TEvent.WaitFor(time);
и т. д.
p.s. Немного раздражает, что документации по лазарю как кот наплакал
Дополнение(оставляю для потомков
Есть модуль syncobjs (благо еще и идет комплектом)
Вместо СreateEvent() идет TEvent.Create();
Вместо WaitForSingleObject соответственно TEvent.WaitFor(time);
и т. д.
Re: Многопоточные приложения и связанное с ними в Linux, Mac
SovNarKom можно попробовать мое решение viewtopic.php?f=10&t=11509
Re: Многопоточные приложения и связанное с ними в Linux, Mac
Я вот единственное что понять не могу, почему я не могу "разбудить" поток из другого потока?
Приложение консольное.
Во всех случаях ловим исключение и получаем месседж.
Если же попытаться разбудить скажем так (в главном потоке)
То поток просыпается.
В чем может быть подвох?.
Приложение консольное.
Код: Выделить всё
if ((AwakeScheduler) and (FScheduler<>nil)) then
begin
try
writeln('Планировщик спит? ',FScheduler^.Suspended);
FScheduler^.AwakeEvent.SetEvent; //не работает
// FScheduler^.Start; - в наглую тоже не хочет
writeln('Awoke scheduler... ok');
except
writeln('Не удалось разбудить');
error:=true;
end;
end;
Во всех случаях ловим исключение и получаем месседж.
Если же попытаться разбудить скажем так (в главном потоке)
Код: Выделить всё
while (input<>'exit') do
begin
readln(input);
....
if input='start' then MainElevator.Start;
end;
// stop program loop
Terminate;
То поток просыпается.
В чем может быть подвох?.
-
MysticCoder
- постоялец
- Сообщения: 154
- Зарегистрирован: 14.09.2013 00:20:28
- Контактная информация:
Re: Многопоточные приложения и связанное с ними в Linux, Mac
Linus писал(а):В чем может быть подвох?.
а ты давай весь код, там и видно будет
Re: Многопоточные приложения и связанное с ними в Linux, Mac
Весь конечно очень много будет кода (легко заплутать), отфильтрую.
главный:
Модуль tasks
главный:
Код: Выделить всё
program server;
{$mode objfpc}{$H+}
{$DEFINE UseCThreads}
uses
{$IFDEF UNIX}{$IFDEF UseCThreads}
cthreads,
{$ENDIF}{$ENDIF}
Classes, SysUtils, CustApp, tasks, net
{ you can add units after this };
type
{ TServer }
TServer = class(TCustomApplication)
protected
procedure DoRun; override;
public
constructor Create(TheOwner: TComponent); override;
destructor Destroy; override;
procedure WriteHelp; virtual;
end;
{ TServer }
procedure TServer.DoRun;
var
ErrorMsg: String;
input:string;
MainElevator:TTaskScheduler;
begin
// parse parameters
if HasOption('h', 'help') then begin
WriteHelp;
Terminate;
Exit;
end;
MainElevator:=TTaskScheduler.create(true);
MainElevator.setup;
MainElevator.Priority:=tpHigher;
//LoadTasks;
//SaveTasks;
{ add your program here }
input:='';
while input<>'exit' do
begin
readln(input);
....
if input='list' then
MainElevator.TasksDB.PrintTasks;
if input='save' then
if MainElevator.TasksDB.SaveTasks then writeln('успешно') else writeln('fail');
if input='load' then
if MainElevator.TasksDB.LoadTasks then writeln('успешно') else writeln('fail');
if input='start' then MainElevator.Start; //запуск процесса (который проблемно будить)
end;
// stop program loop
Terminate;
end;
constructor TServer.Create(TheOwner: TComponent);
begin
inherited Create(TheOwner);
end;
destructor TServer.Destroy;
begin
//close files
inherited Destroy;
end;
procedure TServer.WriteHelp;
begin
{ add your help code here }
writeln('Usage: ', ExeName, ' -h');
end;
var
Application: TServer;
begin
Application:=TServer.Create(nil);
Application.Title:='server';
Application.Run;
Application.Free;
end.
Модуль tasks
Код: Выделить всё
unit tasks;
{$mode objfpc}{$H+}
interface
uses
Classes, SysUtils, Process, LazFileUtils, syncobjs;
const
DataFiles='./DATA';
TaskDB='./tasks.tdb';
type
....
TTaskThread=class(TThread) //поток конкретной задачи (то откуда будем будить)
...
TTaskScheduler=class(TThread) //планировщик (его будем будить)\0
..
AwakeEvent:TEvent;\0
procedure setup;
procedure AwakeMe;\0
..
end;
...
implementation\0
...
procedure TTaskThread.execute;
var
error:boolean;
begin
if (TaskItem=nil)
then writeln('Critiacal ERROR')
else
begin
error:=FALSE;
writeln('****thread log');
//ждем (отложенный запуск)?
TaskItem^.State:=TsSleep;
write('whait=',Delay);
sleep(Delay*1000);
writeln('.......ok');
writeln('Будить планировщик? ',AwakeScheduler);
//"будим планировщик?"
if ((AwakeScheduler) and (FScheduler<>nil)) then
begin
try
writeln('Планировщик спит? ',FScheduler^.Suspended);
FScheduler^.AwakeEvent.SetEvent;
writeln('Awoke scheduler... ok');
except
writeln('Не удалось разбудить');
error:=true;
end;
end;
writeln('конкурирование процесса перед запуском');
//жизнь задачи (нить висит и обслуживает текущую задачу [ожидание, управление, завершение])
....
finally
writeln('процесс умер');
//если мы здесь, то процесс мертв
process.Free;
TaskItem^.State:=TsFree;
//лог писать будем?
writeln('****END log');
end;
end;
end;
...
{TTaskScheduler}
procedure TTaskScheduler.setup;
begin
//инициализация
TasksDB.ini;
ReadyTasks.ini;
AbortedTasks.ini;
//CreateEvent
AwakeEvent:=TEvent.Create(nil, true, false, 'AwakeScheduler');
write('Загрузка задач....');
if TasksDB.LoadTasks then writeln('ok') else writeln('failed');
....
end;
procedure TTaskScheduler.execute;
var
lastChkTask:TTaskItemPTR;
begin
lastChkTask:=nil;
while (not self.Terminated) do
begin
//Анализ...
if (lastChkTask=nil) then lastChkTask:=self.TasksDB.Root;
lastChkTask:=AnalyzeTasks(lastChkTask); //Эта процедура создает экземпляры TTaskThread(они будут будить)
{ранние задачи запущены, пора спать,нас разбудит
первая задача как только начнет выполняться,
наша задача обратотать обновения как проснемся, если такие есть
если нет то просто проделываем то же самое (loop)}
writeln('Suspend Scheduler....ok');
//Ждем событие
AwakeEvent.WaitFor(INFINITE); //время потом исправлю!!
AwakeEvent.ResetEvent;
{проснулись}
if (self.TasksDB.modify) then
begin
.....
end;
end;
end;
Последний раз редактировалось Linus 21.01.2017 18:46:59, всего редактировалось 1 раз.
Re: Многопоточные приложения и связанное с ними в Linux, Mac
Linus писал(а):Весь конечно очень много будет, отфильтрую.
главный:
Попробуйте чистить input:=''; перед выполнением запуска.
Код: Выделить всё
if input='start' then begin input:=''; MainElevator.Start; end;
Re: Многопоточные приложения и связанное с ними в Linux, Mac
vitaly_l писал(а):Linus писал(а):Весь конечно очень много будет, отфильтрую.
главный:
Попробуйте чистить input:=''; перед выполнением запуска.Код: Выделить всё
if input='start' then begin input:=''; MainElevator.Start; end;
Извините, привычка выкладывать по частям. Вся вкусность не там. Просмотрите обновление.
Re: Многопоточные приложения и связанное с ними в Linux, Mac
Linus писал(а):Извините, привычка выкладывать по частям. Вся вкусность не там. Просмотрите обновление.
Эта вкусность ничего не меняет, т.к. вы 1 000 000 раз в секунду запускаете миллион MainElevator.Start; после первых пол секунды у вас должен закипать процессор.
Re: Многопоточные приложения и связанное с ними в Linux, Mac
vitaly_l писал(а):Эта вкусность ничего не меняет, т.к. вы 1 000 000 раз в секунду запускаете миллион MainElevator.Start; после первых пол секунды у вас должен закипать процессор.
А вот и не запускает... С чего он должен запускать если выполнение далее не пройдет пока не отработает Readln();
По логам видно было бы) Проверю еще раз, отпишусь;
Проверил. Перезапусков нет что так что так.
-
MysticCoder
- постоялец
- Сообщения: 154
- Зарегистрирован: 14.09.2013 00:20:28
- Контактная информация:
Re: Многопоточные приложения и связанное с ними в Linux, Mac
собственно, а как
может разбудить это?
Upd. ага, понял, затупил)
Upd.Upd.
Вообще, тут надо просто отладить, непонятно на каком шаге AV возникает, что при этом в логах, что делает в это время поток который должен разбудиться.
Вангую, что в идет попытка разыменовать невалидный указатель. Вообще, непонятно зачем здесь использовать указатель на класс, ведь он сам и есть указатель. Тогда уж проверку выше на nil надо не только FSheduler, а еще и FSheduler^ ставить.
Код: Выделить всё
FScheduler^.AwakeEvent.SetEvent;может разбудить это?
Код: Выделить всё
procedure TTaskScheduler.execute;
...
//Ждем событие
AwakeEvent.WaitFor(INFINITE); //время потом исправлю!!
Upd. ага, понял, затупил)
Upd.Upd.
Вообще, тут надо просто отладить, непонятно на каком шаге AV возникает, что при этом в логах, что делает в это время поток который должен разбудиться.
Вангую, что в
Код: Выделить всё
FScheduler^.SuspendedRe: Многопоточные приложения и связанное с ними в Linux, Mac
Для меня тоже это загадка)
Ладно, понятно что напрямую из главного потока работает.
Для теста создал поток от главного, перенес туда код. (Главный понятно спать sleep уложил, и эти строки закомментил )
И самое главное, это тоже работает. но почему не работает именно та схема, что нужна.
Ладно, понятно что напрямую из главного потока работает.
Для теста создал поток от главного, перенес туда код. (Главный понятно спать sleep уложил, и эти строки закомментил )
Код: Выделить всё
while input<>'exit' do
begin
readln(input);
....
if input='start' then MainElevator.Start; //запуск процесса (который проблемно будить)
end;
И самое главное, это тоже работает. но почему не работает именно та схема, что нужна.
-
MysticCoder
- постоялец
- Сообщения: 154
- Зарегистрирован: 14.09.2013 00:20:28
- Контактная информация:
Re: Многопоточные приложения и связанное с ними в Linux, Mac
так и будем в экстрасенсов играть или покажешь подробнее отладочные данные?
плюс код присваивания FSheduler
MysticCoder писал(а):непонятно на каком шаге AV возникает, что при этом в логах, что делает в это время поток который должен разбудиться.
Вангую, что в
плюс код присваивания FSheduler
