powered by simpleCommunicator - 2.0.61     © 2026 Programmizd 02
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Форумы / Delphi [игнор отключен] [закрыт для гостей] / Шаблон класса для работы с потоком (WThread, Thread)
25 сообщений из 469, страница 8 из 19
Шаблон класса для работы с потоком (WThread, Thread)
    #38859963
Dimonka,

подробнее пожалуйста
...
Рейтинг: 0 / 0
Шаблон класса для работы с потоком (WThread, Thread)
    #38860038
Фотография Dimonka
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Максим УлитинDimonka,

подробнее пожалуйста

Локальные строки как и другие динамические массивы уничтожаются при выходе из процедуры. Если строка тебе нужна в потоке, то необходимо сделать копию строки для потока. Просто полистай эту тему - все ответы здесь уже есть.
...
Рейтинг: 0 / 0
Шаблон класса для работы с потоком (WThread, Thread)
    #38860053
Dimonka,

ну будем считать что мне везло столько лет. Думаю да, Вы правы, но работало ведь

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

думаю после этого глюки пропадут.
...
Рейтинг: 0 / 0
Шаблон класса для работы с потоком (WThread, Thread)
    #38860301
Фотография wadman
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Максим Улитин- сделать так, чтобы везде, где есть фастрепорт, запускалась отдельная процедура для вывода инфы (на экран или там в PDF)
Если исходники фастрепорта есть, то ищи во всех местах вызов Application.ProcessMessages и делай перед этим проверки на опцию многопоточности. Кажется таких мест 5-6. И станет он белым и пушистым.
...
Рейтинг: 0 / 0
Шаблон класса для работы с потоком (WThread, Thread)
    #38860391
wadman,

спасибо, так и сделаю.

А так вчера почистил код в том модуле и избавился от мусора. И потом понял где проблема, это му.... нехороший человек таймер не прибивал. то есть он вроде написал, чтобы таймер прибивался, но сообщение о прибивании таймера забывал посылать.
в итоге написал тестовое приложение с бесконечным циклом на создание массива на 10 лямов рандом значений и сортировку через этот мой класс и оставил на ночь. Ни разу exception не сработал.

так что теперь в думах - вернуть что раньше писал или оставить что есть сейчас. как бы и тогда работало надежно, и сейчас работает по первым прикидкам вроде надежно
...
Рейтинг: 0 / 0
Шаблон класса для работы с потоком (WThread, Thread)
    #38864066
wadman,

Если заюзать юнит в сервисе, обработка сообщений между приложениями работать будет?
Спрашиваю т.к. у сервиса нет окна, и я не очень понимаю как сервисы между собой общаются...
Возможен ли обмен между 2-мя и более сервисами через этот юнит?
...
Рейтинг: 0 / 0
Шаблон класса для работы с потоком (WThread, Thread)
    #38864750
Фотография wadman
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Поток в службе...,

в службе работает без проблем, между службами не пробовал.
...
Рейтинг: 0 / 0
Шаблон класса для работы с потоком (WThread, Thread)
    #38932671
Фотография wadman
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
* Убрал утечки памяти, которые были под fpc.
+ Добавил буфер для отправки сообщений до того, как будет готова очередь
+ Добавил поддержку *nix для fpc

Код: pascal
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
65.
66.
67.
68.
69.
70.
71.
72.
73.
74.
75.
76.
77.
78.
79.
80.
81.
82.
83.
84.
85.
86.
87.
88.
89.
90.
91.
92.
93.
94.
95.
96.
97.
98.
99.
100.
101.
102.
103.
104.
105.
106.
107.
108.
109.
110.
111.
112.
113.
114.
115.
116.
117.
118.
119.
120.
121.
122.
123.
124.
125.
126.
127.
128.
129.
130.
131.
132.
133.
134.
135.
136.
137.
138.
139.
140.
141.
142.
143.
144.
145.
146.
147.
148.
149.
150.
151.
152.
153.
154.
155.
156.
157.
158.
159.
160.
161.
162.
163.
164.
165.
166.
167.
168.
169.
170.
171.
172.
173.
174.
175.
176.
177.
178.
179.
180.
181.
182.
183.
184.
185.
186.
187.
188.
189.
190.
191.
192.
193.
194.
195.
196.
197.
198.
199.
200.
201.
202.
203.
204.
205.
206.
207.
208.
209.
210.
211.
212.
213.
214.
215.
216.
217.
218.
219.
220.
221.
222.
223.
224.
225.
226.
227.
228.
229.
230.
231.
232.
233.
234.
235.
236.
237.
238.
239.
240.
241.
242.
243.
244.
245.
246.
247.
248.
249.
250.
251.
252.
253.
254.
255.
256.
257.
258.
259.
260.
261.
262.
263.
264.
265.
266.
267.
268.
269.
270.
271.
272.
273.
274.
275.
276.
277.
278.
279.
280.
281.
282.
283.
284.
285.
286.
287.
288.
289.
290.
291.
292.
293.
294.
295.
296.
297.
298.
299.
300.
301.
302.
303.
304.
305.
306.
307.
308.
309.
310.
311.
312.
313.
314.
315.
316.
317.
318.
319.
320.
321.
322.
323.
324.
325.
326.
327.
328.
329.
330.
331.
332.
333.
334.
335.
336.
337.
338.
339.
340.
341.
342.
343.
344.
345.
346.
347.
348.
349.
350.
351.
352.
353.
354.
355.
356.
357.
358.
359.
360.
361.
362.
363.
364.
365.
366.
367.
368.
369.
370.
371.
372.
373.
374.
375.
376.
377.
378.
379.
380.
381.
382.
383.
384.
385.
386.
387.
388.
389.
390.
391.
392.
393.
394.
395.
396.
397.
398.
399.
400.
401.
402.
403.
404.
405.
406.
407.
408.
409.
410.
411.
412.
413.
414.
415.
416.
417.
418.
419.
420.
421.
422.
423.
424.
425.
426.
427.
428.
429.
430.
431.
432.
433.
434.
435.
436.
437.
438.
439.
440.
441.
442.
443.
444.
445.
446.
447.
448.
449.
450.
451.
452.
453.
454.
455.
456.
457.
458.
459.
460.
461.
462.
463.
464.
465.
466.
467.
468.
469.
470.
471.
472.
473.
474.
475.
476.
477.
478.
479.
480.
481.
482.
483.
484.
485.
486.
487.
488.
489.
490.
491.
492.
493.
494.
495.
496.
497.
498.
499.
500.
501.
502.
503.
504.
505.
506.
507.
508.
509.
510.
511.
512.
513.
514.
515.
516.
517.
518.
519.
520.
521.
522.
523.
524.
525.
526.
527.
528.
529.
530.
531.
532.
533.
534.
535.
536.
537.
538.
539.
540.
541.
542.
543.
544.
545.
546.
547.
548.
549.
550.
551.
552.
553.
554.
555.
556.
557.
558.
559.
560.
561.
562.
563.
564.
565.
566.
567.
568.
569.
570.
571.
572.
573.
574.
575.
576.
577.
578.
579.
580.
581.
582.
583.
584.
585.
586.
587.
588.
589.
590.
591.
592.
593.
594.
595.
596.
597.
598.
599.
600.
601.
602.
603.
604.
605.
606.
607.
608.
609.
610.
611.
612.
613.
614.
615.
616.
617.
618.
619.
620.
621.
622.
623.
624.
625.
626.
unit WThread;
// модуль для работы с доп.потоками Delphi&Lazarus (win&linux)
// позволяет "общаться" дополнительному и основному потокам посредством очереди сообщений
// (c) wadman 2013-2015, версия от 09.04.2015
//
// использование:
// 1. Создать наследника с объявленными обработчиками сообщений
//  const WM_TEST_PROC = WM_THREAD_BASE + 1;
//  TMyThread = class(TWThread)
//     procedure WMTestProc(var Msg: TThreadMessage); message WM_TEST_PROC;
//  данные процедуры будут выполняться в доп.потоке путем отправки связанного с ними сообщения в поток
//  см. PostToThreadMessage
// 2. Присвоить форме обработчика(ов) события OnThreadReceiveMessage (OnTimeOut - при необходимости)
//
// Для обмена строками рекомендуется использовать функции NewString и FreeString
//
// Для корректной остановки потока и дальнейшей работы программы должна использоваться процедура StopThrad
// При компиляции под *nix в файле проекта до раздела USES вставить строку строку {$DEFINE UseCThreads}
{$IFDEF FPC}
{$mode objfpc}{$H+}
    {$IFDEF WINDOWS}
        {$DEFINE FPC_WIN}
        {$DEFINE ALL_WIN}
    {$ELSE}
        {$DEFINE FPC_NIX}
    {$ENDIF}
{$ELSE}
    {$DEFINE WIN}
    {$DEFINE ALL_WIN}
{$ENDIF}

// для передачи строк между потоками используется выделенная память
{$DEFINE ALLOC_STRING}

interface

uses
    SysUtils,
{$IFDEF UNIX} // добавить эти строки в модуль проекта при разработке не под windows
        //cthreads,
        //cmem,
{$ENDIF}
    Classes,
    Messages
{$IFDEF FPC_WIN}
    ,Windows
{$ENDIF}
{$IFDEF FPC}
    ,SyncObjs
{$ENDIF}
    ;

const
{$IFDEF FPC}
    INFINITE            = Cardinal($FFFFFFFF);
{$ENDIF}
    WM_USER             = $400;
    WM_THREAD_BASE      = WM_USER + $110;
    WM_THREAD_MAX       = WM_USER + $300;

type
    PThreadMessage = ^TThreadMessage;
    TThreadMessage = record
{$IFDEF FPC}
        Message: DWord;
{$ELSE}
        Message: Word;
{$ENDIF}
        WParam: Word;
        LParam: NativeInt;
    end;

    TWThread = class;

        // событие на получение сообщения из потока
    TWThreadReceiveMessage = procedure(Sender: TWThread; var Msg: TThreadMessage) of object;
        // событие из потока на таймаут
    TWThreadTimeOut = procedure(Sender: TWThread) of object;

    TWThread = class(TThread)
    private
{$IFDEF FPC}
        FQueue: TList;
        FSection: TCriticalSection;
        FMessageEvent: TEvent;
        FGUIThread: TThread;
{$ELSE}
        FQueueReady: boolean;
        FQueueMessages: array of TThreadMessage;
        FToolWindow: THandle;
        hCloseEvent: THandle;
{$ENDIF}
        FOnThreadReceiveMessage: TWThreadReceiveMessage;
        FOnTimeOut: TWThreadTimeOut;
        FTimeOutIsDirect: boolean;
        procedure SetTimeOut(const Value: Cardinal);
    protected
        FTimeOut: Cardinal;
{$IFNDEF FPC}
        FWindowHandle: THandle;
        procedure WWindowProc(var Msg: TMessage);
        procedure GetWindow;
        procedure FreeWindow;
{$ENDIF}
            // отправка сообщения из этого потока для вызова обработчика OnThreadReceiveMessage
        procedure PostMessageFromThread(const Msg: Word; const WParam: Word; const LParam: NativeInt);
        procedure DoThreadReceiveMessage(const Msg: Word; const WParam: Word; const LParam: NativeInt);
        procedure DoTimeout;
        procedure Execute; override;
        function GetTimeOut: Cardinal; virtual;
    public
        constructor Create; overload;
        constructor Create(CreateSuspended: Boolean); overload;
        destructor Destroy; override;
        procedure InitThread; virtual;
        procedure DoneThread; virtual;
            // см TimeOutIsDirect, при true - перекрыть следующую процедуру
        procedure DirectTimeOut; virtual;
            // отправка любого сообщения В этот поток
        function PostToThreadMessage(const Msg: Word; const WParam: Word; const LParam: NativeInt): Boolean;
            // остановка потока по феншую
        procedure StopThread;
            // событие на получение данных ИЗ этого потока, вызывается в основном потоке
        property OnThreadReceiveMessage: TWThreadReceiveMessage read FOnThreadReceiveMessage write FOnThreadReceiveMessage;
            // событие, возникающее при превышении интервала ожидания
        property OnTimeOut: TWThreadTimeOut read FOnTimeOut write FOnTimeOut;
            // интервал ожидания в мс, по-умолчанию - бесконечно
        property TimeOut: Cardinal read GetTimeOut write SetTimeOut default INFINITE;
            // true = Будет вызван DirectTimeOut из этого потока, false = вызвано событие OnTimeOut в основном потоке.
        property TimeOutIsDirect: boolean read FTimeOutIsDirect write FTimeOutIsDirect default false;
    end;

    // подготовка строки к обмену между потоками
function NewString(const Text: string): NativeInt;

    // возвращение строки к привычному виду после приема из другого потока
function FreeString(var P: NativeInt): String;

implementation

{$IFNDEF FPC}
uses Windows;
{$ENDIF}

const
{$IFDEF ALL_WIN}
    WM_THREAD_READY     = WM_USER+$102;
{$ENDIF}
    WM_TIMEOUT          = WM_USER+$101;

    SizeOfChar          = SizeOf(Char);


{$IFDEF ALLOC_STRING}
{$IFDEF ALL_WIN}
// для передачи строки между программами
function GlobalNewString(const Text: string): NativeInt;
var l: Integer;
    p: pointer;
begin
    l := Length(Text)*SizeOfChar;
    if L > SizeOfChar then begin
        Result := GlobalAlloc(GHND, l+SizeOfChar);
        if LongBool(Result) then begin
            p := GlobalLock(Result);
            Move(Pointer(Text)^, Pointer(p)^, l);
            GlobalUnlock(Result);
        end
    end else
        Result := 0;
end;

// для передачи строки между программами
function GlobalFreeString(var P: NativeInt): String;
var ps: pointer;
begin
    if LongBool(P) then begin
        ps := GlobalLock(P);
        SetLength(Result, Length(PChar(ps)));
        Move(Pointer(ps)^, Pointer(Result)^, Length(Result)*SizeOfChar);
        GlobalUnlock(P);
        P := GlobalFree(P);
    end;
end;
{$ENDIF}

// для передачи строки в пределах одной программы
function FreeString(var P: NativeInt): String;
begin
    if LongBool(P) then begin
        SetLength(Result, Length(PChar(P)));
        Move(Pointer(P)^, Pointer(Result)^, Length(Result)*SizeOfChar);
{$IFDEF ALL_WIN}
        P := LocalFree(HLOCAL(P));
{$ELSE}
        P := FreeMem(Pointer(P));
{$ENDIF}
    end;
end;

// для передачи строки в пределах одной программы
function NewString(const Text: string): NativeInt;
var l: Integer;
begin
    l := Length(Text)*SizeOfChar;
    if L > SizeOfChar then begin
{$IFDEF ALL_WIN}
        Result := LocalAlloc(LPTR, l+SizeOfChar);
{$ELSE}
        Pointer(Result) := AllocMem(l+SizeOfChar);
{$ENDIF}
        if LongBool(Result) then
            Move(Pointer(Text)^, Pointer(Result)^, l);
    end else
        Result := 0;
end;
{$ELSE}
function NewString(const Text: string): NativeInt;
begin
    Result := 0;
    string(Result) := Text;
end;

function FreeString(var P: NativeInt): String;
begin
    NativeInt(Result) := P;
end;
{$ENDIF}

{$IFDEF FPC}
type

    { TGUIThread }

    TGUIThread = class(TThread)
    private
        FMessageEvent: TEvent;
        FTimeOut: Boolean;
        FOwner: TWThread;
        FQueue: TList;
        FSection: TCriticalSection;
        FCurrentMessage: TThreadMessage;
    protected
        procedure Execute; override;
        procedure CallGUIThread;
    public
        constructor Create(AOwner: TWThread); overload;
        destructor Destroy; override;
        procedure PostMessage(const Message: DWord; const WParam: Word; const LParam: NativeInt);
        procedure StopThread;
    end;

{ TGUIThread }

procedure FreeQueue(const List: TList);
var i: integer;
begin
    for i := 0 to List.Count-1 do
        FreeMem(List[i]);
end;

procedure TGUIThread.Execute;
var Message: PThreadMessage;
    wr: TWaitResult;
begin
    while not Terminated do begin
        wr := FMessageEvent.WaitFor(INFINITE);
        if (not Terminated) and (wr = wrSignaled) then begin
            if FTimeOut then begin
                FTimeOut := False;
                if Assigned(FOwner.FOnTimeOut) then
                    FOwner.FOnTimeOut(FOwner);
            end;
            while FQueue.Count > 0 do begin
                FSection.Enter;
                Message := FQueue[0];
                FQueue.Delete(0);
                FSection.Leave;
                FCurrentMessage := Message^;
                FreeMem(Message);
                if (FCurrentMessage.Message >= WM_THREAD_BASE)
                    and(FCurrentMessage.Message <= WM_THREAD_MAX) then
                    Synchronize(@CallGUIThread);
            end;
        end;
    end;
end;

procedure TGUIThread.CallGUIThread;
begin
    if Assigned(FOwner) then
        FOwner.DoThreadReceiveMessage(FCurrentMessage.Message, FCurrentMessage.WParam, FCurrentMessage.LParam);
end;

constructor TGUIThread.Create(AOwner: TWThread);
begin
    inherited Create(False);
    FMessageEvent := TEvent.Create(nil, False, False, '');
    FQueue := TList.Create;
    FSection := TCriticalSection.Create;
    FOwner := AOwner;
end;

destructor TGUIThread.Destroy;
begin
    FreeQueue(FQueue);
    FSection.Free;
    FQueue.Free;
    FMessageEvent.Free;
    inherited Destroy;
end;

procedure TGUIThread.PostMessage(const Message: DWord; const WParam: Word; const LParam: NativeInt);
var Msg: PThreadMessage;
begin
    GetMem(Msg, SizeOf(TThreadMessage));
    Msg^.Message := Message;
    Msg^.WParam := WParam;
    Msg^.LParam := LParam;
    FSection.Enter;
    FQueue.Add(Msg);
    FSection.Leave;
    FMessageEvent.SetEvent;
end;

procedure TGUIThread.StopThread;
begin
    Terminate;
    FMessageEvent.SetEvent;
end;
{$ENDIF}

{ TWThread }

constructor TWThread.Create(CreateSuspended: Boolean);
begin
    inherited Create(CreateSuspended);
{$IFDEF FPC}
    FQueue := TList.Create;
    FMessageEvent := TEvent.Create(nil, False, False, '');
    FSection := TCriticalSection.Create;
    FGUIThread := TGUIThread.Create(Self);
{$ELSE}
    hCloseEvent := CreateEvent(nil, false, false, nil);
    GetWindow;
    FWindowHandle := 0;
    FQueueReady := False;
{$ENDIF}
    FTimeOut := INFINITE;
    FTimeOutIsDirect := False;
end;

constructor TWThread.Create;
begin
    Create(False);
end;

destructor TWThread.Destroy;
begin
{$IFDEF FPC}
    FMessageEvent.Free;
    FreeQueue(FQueue);
    FQueue.Free;
    FGUIThread.Free;
    FSection.Free;
{$ELSE}
    CloseHandle(hCloseEvent);
{$ENDIF}
    inherited;
end;

procedure TWThread.DirectTimeOut;
begin
    // override
end;

procedure TWThread.InitThread;
begin
    // empty
end;

procedure TWThread.DoneThread;
begin
    // empty
end;

procedure TWThread.DoThreadReceiveMessage(const Msg: Word; const WParam: Word; const LParam: NativeInt);
var ThreadMsg: TThreadMessage;
begin
    if Assigned(FOnThreadReceiveMessage) then begin
        ThreadMsg.Message := Msg;
        ThreadMsg.WParam := WParam;
        ThreadMsg.LParam := LParam;
        FOnThreadReceiveMessage(Self, ThreadMsg);
    end;
end;

procedure TWThread.DoTimeout;
begin
{$IFDEF FPC}
    TGUIThread(FGUIThread).FTimeOut := true;
    TGUIThread(FGUIThread).FMessageEvent.SetEvent;
{$ELSE}
    if Assigned(FOnTimeOut) then
        FOnTimeOut(Self);
{$ENDIF}
end;

function TWThread.PostToThreadMessage(const Msg: Word; const WParam: Word; const LParam: NativeInt): boolean;
{$IFDEF FPC}
var PMsg: PThreadMessage;
begin
    GetMem(PMsg, SizeOf(TThreadMessage));
    PMsg^.Message := Msg;
    PMsg^.WParam := WParam;
    PMsg^.LParam := LParam;
    FSection.Enter;
    FQueue.Add(PMsg);
    FSection.Leave;
    FMessageEvent.SetEvent;
    result := true;
{$ELSE}
begin
    if FQueueReady then begin
        // если очередь сообщений создана и поток инициализирован, то сразу отправляем
        result := (not Suspended)and(PostThreadMessage(ThreadID, Msg, wParam, lParam));
    end else begin
        // иначе кэшируем
        SetLength(FQueueMessages, Length(FQueueMessages)+1);
        FQueueMessages[High(FQueueMessages)].Message := Msg;
        FQueueMessages[High(FQueueMessages)].WParam := WParam;
        FQueueMessages[High(FQueueMessages)].LParam := LParam;
        result := True;
    end;
{$ENDIF}
end;

procedure TWThread.SetTimeOut(const Value: Cardinal);
begin
{$IFDEF FPC}
    if FTimeOut <> Value then begin
        FTimeOut := Value;
        if not Suspended then
            FMessageEvent.SetEvent;
    end;
{$ELSE}
    if FTimeOut <> Value then begin
        FTimeOut := Value;
        if (not Suspended)and(GetCurrentThreadId <> ThreadID) then
            PostThreadMessage(ThreadID, WM_TIMEOUT, Value, 0);
    end;
{$ENDIF}
end;

procedure TWThread.Execute;
var
{$IFDEF FPC}
    Message: PThreadMessage;
    wr: TWaitResult;
begin
    InitThread;
    while not Terminated do begin
        wr := FMessageEvent.WaitFor(FTimeOut);
        if not Terminated then
            case WR of
                wrSignaled: while FQueue.Count > 0 do begin
                    FSection.Enter;
                    Message := FQueue[0];
                    FQueue.Delete(0);
                    FSection.Leave;
                    if (Message^.message >= WM_THREAD_BASE)
                        and (Message^.Message <= WM_THREAD_MAX) then
                            Dispatch(Message^);
                    FreeMem(Message);
                end;
                wrTimeout: begin
                    if FTimeOutIsDirect then
                        DirectTimeOut
                    else
                        PostMessageFromThread(WM_TIMEOUT, 0, 0);
                end;
            end;
    end;
{$ELSE}
    message: TThreadMessage;
    HandlesToWaitFor: array [0 .. 0] of THandle;
    dwHandleSignaled: DWORD;
    msg: TMsg;

begin
    // следующая строка должна быть всегда первой в процедуре, т.к. запускает очередь сообщений для потока
    PeekMessage(msg, THandle(-1), WM_USER, WM_USER, PM_NOREMOVE);
    InitThread;
    PostMessageFromThread(WM_THREAD_READY, 0, 0);
    HandlesToWaitFor[0] := hCloseEvent;
    // SleepEx не нужен, если подготовительный код до цикла while будет достаточно долго выполняться
    // уточняется опытным путем, иначе очередь сообщений потока не успеет запуститься и сообщения могут улететь в пустоту
    //SleepEx(20, true);

    while not Terminated do begin
        if ((FWindowHandle = 0) and(not PeekMessage(msg, THandle(-1), WM_THREAD_BASE, WM_THREAD_MAX, PM_REMOVE)))
            or((FWindowHandle <> 0) and (
                (not PeekMessage(msg, FWindowHandle, 0, 0, PM_REMOVE))
                and
                (not PeekMessage(msg, THandle(-1), WM_THREAD_BASE, WM_THREAD_MAX, PM_REMOVE))
            )) then begin

            if (FWindowHandle = 0) then
                dwHandleSignaled := MsgWaitForMultipleObjects(1, HandlesToWaitFor, false, TimeOut, QS_ALLINPUT)
            else
                dwHandleSignaled := MsgWaitForMultipleObjects(1, HandlesToWaitFor, false, TimeOut, QS_ALLEVENTS);

            case dwHandleSignaled of
                WAIT_OBJECT_0: begin // выставлено событие остановки потока
                    if not FreeOnTerminate then
                        Terminate;
                    break;
                end;
                WAIT_OBJECT_0 + 1: begin // получено сообщение
                    Continue;
                end;
                WAIT_TIMEOUT: begin
                    if FTimeOutIsDirect then
                        DirectTimeOut
                    else
                        PostMessageFromThread(WM_TIMEOUT, 0, 0);
                    Continue;
                end;
            end;
        end;

        if Terminated then break;

        if LongBool(FWindowHandle) and (FWindowHandle = msg.hwnd) then begin
            // хэндл окна присвоен и пришло сообщение для окна
            TranslateMessage(msg);
            DispatchMessage(msg);
        end else case msg.message of
            WM_TIMEOUT: begin
                FTimeOut := msg.wParam;
            end;
            WM_THREAD_BASE..WM_THREAD_MAX: begin
                message.Message := Msg.message;
                message.WParam := Msg.wParam;
                message.LParam := Msg.lParam;
                // ищем и вызываем procedure of object message
                Dispatch(message);
            end;
        end;
    end;
{$ENDIF}
    DoneThread;
end;

procedure TWThread.PostMessageFromThread(const Msg: Word; const WParam: Word; const LParam: NativeInt);
begin
{$IFDEF FPC}
    if Assigned(FGUIThread) then
        TGUIThread(FGUIThread).PostMessage(Msg, WParam, LParam);
{$ELSE}
    if FToolWindow <> 0 then begin
        PostMessage(FToolWindow, Msg, WParam, LParam);
    end;
{$ENDIF}
end;

procedure TWThread.StopThread;
begin
{$IFDEF FPC}
    TGUIThread(FGUIThread).StopThread;
    Terminate;
    FMessageEvent.SetEvent;
{$ELSE}
    FreeWindow;
    Terminate;
    SetEvent(hCloseEvent);
    //SleepEx(1, false);
    //result := WaitForSingleObject(Handle, 10000) <> WAIT_TIMEOUT;
{$ENDIF}
end;

function TWThread.GetTimeOut: Cardinal;
begin
    Result := FTimeOut;
end;

{$IFNDEF FPC}

procedure TWThread.WWindowProc(var Msg: TMessage);
var i: integer;
begin
    case Msg.Msg of
        WM_TIMEOUT: begin
            DoTimeout;
            Msg.Result := 1;
        end;
        WM_THREAD_READY: begin
            FQueueReady := true;
            // поток готов, отправляем ему все закэшированные сообщения
            if Length(FQueueMessages) > 0 then for i := Low(FQueueMessages) to High(FQueueMessages) do
                PostToThreadMessage(FQueueMessages[i].Message, FQueueMessages[i].WParam, FQueueMessages[i].LParam);
            SetLength(FQueueMessages, 0);
        end;
        WM_THREAD_BASE..WM_THREAD_MAX: begin
            DoThreadReceiveMessage(Msg.Msg, Msg.WParam, Msg.LParam);
            Msg.Result := 1;
        end
    else  if LongBool(FToolWindow) then
        Msg.Result := DefWindowProc(FToolWindow, Msg.Msg, Msg.wParam, Msg.lParam);
    end;
end;

procedure TWThread.GetWindow;
begin
    FToolWindow := AllocateHWnd(WWindowProc);
end;

procedure TWThread.FreeWindow;
begin
    DeallocateHWnd(FToolWindow);
    FToolWindow := 0;
end;

{$ENDIF}

end.

...
Рейтинг: 0 / 0
Шаблон класса для работы с потоком (WThread, Thread)
    #38934663
Aleksandr Sharahov
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
wadman,

я бы заменил

Код: pascal
1.
2.
3.
4.
function FreeString(var P: NativeInt): String;
begin
    NativeInt(Result) := P;
end;



на

Код: pascal
1.
2.
3.
4.
5.
function FreeString(var P: NativeInt): String;
begin
    Result := '';
    NativeInt(Result) := P;
end;
...
Рейтинг: 0 / 0
Шаблон класса для работы с потоком (WThread, Thread)
    #38934665
Фотография wadman
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Aleksandr Sharahov, я этим совсем не пользуюсь. На что это влияет?
...
Рейтинг: 0 / 0
Шаблон класса для работы с потоком (WThread, Thread)
    #38934688
Aleksandr Sharahov
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
wadman,

на утечку, разумеется
...
Рейтинг: 0 / 0
Шаблон класса для работы с потоком (WThread, Thread)
    #38934725
Фотография wadman
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Aleksandr Sharahovна утечку, разумеется
Раз назвался груздемзнатоком... Поясни, сколько такая строка может прожить? К примеру, если идет долгая обработка одной команды, а в очереди несколько минут висит следующая с такой строкой - какие гарантии, что не затрется?

П.С. Спасибо, учту.
...
Рейтинг: 0 / 0
Шаблон класса для работы с потоком (WThread, Thread)
    #38934734
fd00ch
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
wadman, видимо, тебе намекают, что Result на входе вовсе не обязан быть пустой строкой, и своим хаком ты похеришь старое значение без отработки счетчика ссылок
...
Рейтинг: 0 / 0
Шаблон класса для работы с потоком (WThread, Thread)
    #38934745
Фотография wadman
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
fd00chчто Result на входе вовсе не обязан быть пустой строкой
Это новость для меня...
...
Рейтинг: 0 / 0
Шаблон класса для работы с потоком (WThread, Thread)
    #38934748
Aleksandr Sharahov
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
wadman,

Не совсем понял, о какой "такой" строке ты спрашиваешь.

Если речь об утечке, то там все просто. Строка, которая используется твоей функцией в качестве результата, приходит в нее из вызывающей процедуры и вовсе не обязана быть пустой. Поэтому ее необходимо финализировать, прежде чем жестко менять адрес данных.
...
Рейтинг: 0 / 0
Шаблон класса для работы с потоком (WThread, Thread)
    #38934756
Фотография wadman
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Aleksandr SharahovНе совсем понял, о какой "такой" строке ты спрашиваешь.
О такой, которую получили функцией NewString (FreeString обратная ей).
Код: pascal
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
function NewString(const Text: string): NativeInt;
begin
    Result := 0;
    string(Result) := Text;
end;

function FreeString(var P: NativeInt): String;
begin
    NativeInt(Result) := P;
end;


Aleksandr SharahovСтрока, которая используется твоей функцией в качестве результата, приходит в нее из вызывающей процедуры и вовсе не обязана быть пустой.
Торможу чего-то... Как результат этой функции приходит из вызывающей её процедуры?
...
Рейтинг: 0 / 0
Шаблон класса для работы с потоком (WThread, Thread)
    #38934768
fd00ch
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
примерно таким:
Код: pascal
1.
procedure FreeString(var P: NativeInt; var Result: String);
...
Рейтинг: 0 / 0
Шаблон класса для работы с потоком (WThread, Thread)
    #38934772
Фотография wadman
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
fd00chпримерно таким:
Код: pascal
1.
procedure FreeString(var P: NativeInt; var Result: String);


Ты мне шаблон поломал... Давно догадывался, но не хотелось верить и копаться там. :)
...
Рейтинг: 0 / 0
Шаблон класса для работы с потоком (WThread, Thread)
    #38934774
Фотография wadman
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Точно не шутите, что результат может быть определен на входе?
...
Рейтинг: 0 / 0
Шаблон класса для работы с потоком (WThread, Thread)
    #38934802
Aleksandr Sharahov
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
wadmanО такой, которую получили функцией NewString (FreeString обратная ей).

А если об этой, то будет жить, пока живо сообщение.

wadmanТочно не шутите, что результат может быть определен на входе?

А сегодня первое?
...
Рейтинг: 0 / 0
Шаблон класса для работы с потоком (WThread, Thread)
    #38934806
fd00ch
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
wadmanТочно не шутите, что результат может быть определен на входе? http://docwiki.embarcadero.com/RADStudio/XE7/en/Program_Control The following conventions are used for returning function result values.
For a string, dynamic array, method pointer, or variant result, the effects are the same as if the function result were declared as an additional var parameter following the declared parameters. In other words, the caller passes an additional 32-bit pointer that points to a variable in which to return the function result.
...
Рейтинг: 0 / 0
Шаблон класса для работы с потоком (WThread, Thread)
    #38934821
Фотография wadman
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Aleksandr SharahovА сегодня первое?
Не все ограничиваются только первым числом.
Aleksandr SharahovА если об этой, то будет жить, пока живо сообщение.
Нужно будет погонять на сотне-другой потоков. Помнится, этот механизм валился на больших количествах передаваемых строк между потоками. Может как раз из-за этой "мелочи"...

fd00ch, спасибо.
...
Рейтинг: 0 / 0
Шаблон класса для работы с потоком (WThread, Thread)
    #38935293
kealon(Ruslan)
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
wadman, тоже кстати пытался что-то подобное делать
у вас я смотрю по теме большой опыт
немного с другой стороны подошёл (связь односторонняя и полностью стандартными библами fpc)

Код: pascal
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
65.
66.
67.
68.
69.
70.
71.
72.
73.
74.
75.
76.
77.
78.
79.
80.
81.
82.
83.
84.
85.
86.
87.
88.
89.
90.
91.
92.
93.
94.
95.
96.
97.
98.
99.
100.
101.
102.
103.
104.
105.
106.
107.
108.
109.
110.
111.
112.
113.
114.
115.
116.
117.
118.
119.
120.
121.
122.
unit Channels;

interface
uses SysUtils,SyncObjs,Queues;

type

  { TSomeChannel }

  TSomeChannel=class(TInterfacedObject)
   protected
     NeadQuit:boolean;
     Stoper:array[boolean] of TCriticalSection;
     StoperFlag:boolean;
     Locker:TCriticalSection;
   public
     constructor Create;
     destructor Destroy;override;
     procedure Close;
  end;

 { Channel }

 // one writer-creator, many readers not in created thread
 // only created thread can write and close
  generic Channel <T,TFIFO>=class(TSomeChannel)
   private
    FIFO:TFIFO;
    function GetDataExists: boolean;
   protected

   public
    destructor Destroy;override;

    property DataExists:boolean read GetDataExists;
    function Get(out Data:T):boolean;
    procedure Put(const Data:T);
  end;

implementation

{ TSomeChannel }

constructor TSomeChannel.Create;
begin
  inherited;
  Stoper[false]:=TCriticalSection.Create;
  Stoper[true]:=TCriticalSection.Create;
  Locker:=TCriticalSection.Create;

  Stoper[StoperFlag].Enter;
end;

destructor TSomeChannel.Destroy;
begin
  //wait  Reader=0;
  if not NeadQuit then begin
    Close;
  end;

  FreeAndNil(Stoper[false]);
  FreeAndNil(Stoper[true]);
  FreeAndNil(Locker);
  inherited;
end;

procedure TSomeChannel.Close;
begin
  NeadQuit:=true;
  if Assigned(Stoper[StoperFlag]) then begin
    Stoper[StoperFlag].Leave;
  end;
end;


{ Channel }

function Channel.Get(out Data: T): boolean;
var
 S:TCriticalSection;
begin
    repeat
        Locker.Enter; // wait push data
        try
          if FIFO.PopFront(Data) then exit(true);
          S:=Stoper[StoperFlag];
        finally
          Locker.Leave;
        end;
        if NeadQuit then exit(false);
        S.Enter;
        S.Leave;
    until false;
end;

function Channel.GetDataExists: boolean;
begin
  Result:=not FIFO.isEmpty;
end;

destructor Channel.Destroy;
begin
  inherited Destroy;
  FIFO.Clear;
end;

procedure Channel.Put(const Data: T);
begin
  Locker.Enter;
  try
      if FIFO.isEmpty then begin
        Stoper[StoperFlag].Leave;
        StoperFlag:=not StoperFlag;
        Stoper[StoperFlag].Enter;
      end;
      FIFO.PushBack(Data);
  finally
    Locker.Leave;
  end;
end;

end.


ну и очередь для этого простая
Код: pascal
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
65.
66.
67.
68.
69.
70.
71.
72.
73.
74.
75.
76.
77.
78.
79.
80.
81.
82.
83.
84.
85.
86.
87.
88.
89.
90.
91.
92.
93.
94.
95.
96.
97.
98.
99.
100.
101.
102.
103.
104.
105.
106.
107.
108.
109.
110.
111.
112.
113.
114.
115.
116.
117.
118.
119.
120.
121.
122.
123.
124.
125.
126.
127.
128.
129.
130.
131.
132.
133.
134.
135.
136.
137.
138.
139.
140.
141.
142.
143.
144.
145.
146.
147.
148.
149.
150.
151.
152.
153.
154.
155.
156.
157.
158.
159.
160.
161.
162.
163.
164.
165.
166.
167.
168.
169.
170.
171.
172.
173.
174.
175.
176.
177.
178.
179.
180.
181.
182.
183.
184.
185.
186.
187.
188.
189.
190.
191.
192.
193.
194.
195.
196.
197.
198.
199.
200.
201.
202.
203.
204.
205.
206.
207.
208.
209.
210.
211.
212.
213.
214.
215.
216.
217.
218.
219.
220.
221.
222.
223.
224.
225.
226.
227.
228.
229.
230.
231.
232.
233.
234.
235.
unit Queues;

{$mode objfpc}{$H+}

interface

type

  { Deque }

  generic Deque<T>=object
   protected
    type
    PDeq=^TDeq;
    TDeq=record
     Next,Prev:PDeq;
     Data:T;
    end;
   protected
    First,Last:PDeq;
    procedure ClearRec(R:PDeq);inline;
   public
    function isEmpty:boolean;inline;
    function PopBack(out res:T):boolean;
    function PopFront(out res:T):boolean;
    procedure PushBack(const v:T);
    procedure PushFront(const v:T);

    procedure Clear;
    procedure Init;
  end;


  { Queue }

  generic Queue<T>=object    // cicle buffer
   protected
    type
    PFIFORec=^TFIFOREC;
    TFIFORec=record
     Next:PFIFORec;
     Data:T;
    end;
   protected
    Last:PFIFOREC;
    procedure ClearRec(R:PFIFORec);inline;
    function PushFrontInternal(const v:T):PFIFOREC;inline;
   public
    function isEmpty:boolean;inline;
    function PopFront(out res:T):boolean;

    procedure PushBack(const v:T);
    procedure PushFront(const v:T);
    procedure Clear;
    procedure Init;
  end;


implementation

{ Queue }

procedure Queue.ClearRec(R: PFIFORec);
begin
  Finalize(R^);
  Dispose(R);
end;

function Queue.PushFrontInternal(const v: T): PFIFOREC;
var e:PFIFOREC;
begin
  New(e);
  e^.Data:=v;

  if Last<>nil then begin
    e^.Next:=Last^.Next;
    Last^.Next:=e;
  end else begin
    e^.Next:=e;
    Last:=e;
  end;
  Result:=e;
end;

function Queue.isEmpty: boolean;
begin
  Result:=(Last=nil);
end;

function Queue.PopFront(out res: T): boolean;
var e,d:PFIFOREC;
begin
  if isEmpty then exit(false);
  e:=Last^.Next;

  res:=e^.Data;
  d:=e^.Next;
  ClearRec(e);

  if e<>Last then begin
    Last^.Next:=d;
  end else begin
    Last:=nil;
  end;
  Result:=true;
end;

procedure Queue.PushBack(const v: T);
begin
  Last:=PushFrontInternal(v);
end;

procedure Queue.PushFront(const v: T);
begin
  PushFrontInternal(v);
end;

procedure Queue.Clear;
var e,d:PFIFORec;
begin
  if isEmpty then exit;
  e:=Last;

  repeat
   d:=e^.Next;
   ClearRec(e);
   e:=d;
  until e=Last;
  Last:=nil;
end;

procedure Queue.Init;
begin
  Last:=nil;
end;

{ Deque }

procedure Deque.ClearRec(R: PDeq);
begin
  Finalize(R^);
  Dispose(R);
end;

function Deque.isEmpty: boolean;
begin
  Result:=(First=nil);
end;

function Deque.PopBack(out res: T): boolean;
var e:PDeq;
begin
  if isEmpty then exit(false);
  e:=Last;
  res:=e^.Data;
  Last:=e^.Prev;
  ClearRec(e);

  if Last<>nil then begin
    Last^.Next:=nil;
  end else begin
    First:=nil;
  end;
  Result:=true;
end;

function Deque.PopFront(out res: T): boolean;
var e:PDeq;
begin
  if isEmpty then exit(false);
  e:=First;
  res:=e^.Data;
  First:=e^.Next;
  ClearRec(e);

  if First<>nil then begin
    First^.Prev:=nil;
  end else begin
    Last:=nil;
  end;
  Result:=true;
end;

procedure Deque.PushBack(const v: T);
var e:PDeq;
begin
  New(e);
  e^.Data:=v;
  e^.Prev:=Last;
  e^.Next:=nil;

  if Last<>nil then begin
    Last^.Next:=e;
  end else begin
    First:=e;
  end;
  Last:=e;
end;

procedure Deque.PushFront(const v: T);
var e:PDeq;
begin
  New(e);
  e^.Data:=v;
  e^.Prev:=nil;
  e^.Next:=First;

  if First<>nil then begin
    First^.Prev:=e;
  end else begin
    Last:=e;
  end;
  First:=e;
end;

procedure Deque.Clear;
var e,d:PDeq;
begin
  e:=First;
  while e<>nil do begin
   d:=e^.Next;
   ClearRec(e);
   e:=d;
  end;
  First:=nil;
  Last:=nil;
end;

procedure Deque.Init;
begin
  First:=nil;
  Last:=nil;
end;

end.


используется в потоке
Код: pascal
1.
while SomeChanel.get(data) do ...
...
Рейтинг: 0 / 0
Шаблон класса для работы с потоком (WThread, Thread)
    #38935508
Фотография wadman
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
kealon(Ruslan)(связь односторонняя и полностью стандартными библами fpc)
У меня двусторонняя и тоже полностью стандартными. :) Особо в код не вникал... Есть какие-то преимущества?
...
Рейтинг: 0 / 0
Шаблон класса для работы с потоком (WThread, Thread)
    #38936300
kealon(Ruslan)
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
wadman,

основное было делить задачи на несколько потоков
т.е. 1 диспетчер раскидывает задания на несколько потоков
...
Рейтинг: 0 / 0
25 сообщений из 469, страница 8 из 19
Форумы / Delphi [игнор отключен] [закрыт для гостей] / Шаблон класса для работы с потоком (WThread, Thread)
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]