Добро пожаловать в форум, Guest  >>   Войти | Регистрация | Поиск | Правила | В избранное | Подписаться
Все форумы / Delphi Новый топик    Ответить
Топик располагается на нескольких страницах: [1] 2   вперед  Ctrl      все
 CreateThread - проблемы выполнения  [new]
Где то там
Member

Откуда:
Сообщений: 452
Вот кусок кода, с помощью которого я вызываю диалог на время выполнения операции. При инициализации, диалог отдает свой хэндл, чтобы потом его можно было закрыть. Но это происходит не всегда. В чём может быть причина?

var
hPreLoad : HWND;
Dummy : DWORD;
hThread : HWND;

//---------------------------------------------------------

function PreLoadDialogProc(hWndDlg : HWND; Msg : Longint; wParam, lParam : Longint) : Boolean; stdcall;
begin
Result := False;
case Msg of
// не всегда выполняется
WM_INITDIALOG : hPreLoad := hWndDlg;
WM_COMMAND:
case LOWORD(wParam) of
IDOK,
IDCANCEL : EndDialog(hWndDlg, ord(True));
end;
end;
end;

//---------------------------------------------------------

procedure PreLoadDialogThread;
begin
DialogBox(hInstance, 'ID_PRELOADDLG', 0, @PreLoadDialogProc);
end;

//---------------------------------------------------------

begin
...
hThread := CreateThread(NIL, 0, @PreLoadDialogThread, NIL, 0, Dummy);
... // выполняемая задача
SendMessage(hPreLoad, WM_COMMAND, IDOK, 0); // Не всегда hPreload известен, иногда 0
hPreload := 0;
if hThread <> 0 then
begin
WaitForSingleObject(hThread, INFINITE);
CloseHandle(hThread);
hThread := 0;
end;
...
end;
10 авг 08, 20:29    [6049670]     Ответить | Цитировать Сообщить модератору
 Re: CreateThread - проблемы выполнения  [new]
Где то там
Member

Откуда:
Сообщений: 452
Жаль отредактировать нельзя, забыл выделить кодом.
10 авг 08, 20:33    [6049676]     Ответить | Цитировать Сообщить модератору
 Re: CreateThread - проблемы выполнения  [new]
C#C++
Member [заблокирован]

Откуда: Суровые северные земли
Сообщений: 2636
Типичная ошибка многопоточного программирования ))
hPreLoad во втором потоке не успевает инициализироваться перед тем, как его использует SendMessage в первом.
Используйте Event (функции CreateEvent, SetEvent и WaitForSingleObject, см. хелп)

Кстати, PreLoadDialogThread должна быть функцией
function PreLoadDialogThread(p:DWORD):DWORD
10 авг 08, 20:41    [6049688]     Ответить | Цитировать Сообщить модератору
 Re: CreateThread - проблемы выполнения  [new]
Где то там
Member

Откуда:
Сообщений: 452
автор
Кстати, PreLoadDialogThread должна быть функцией
function PreLoadDialogThread(p:DWORD):DWORD


Ну она и так функция. Нигде не сказано, что я не могу объявить её Boolean. А вот про Event нужно почитать, чем он в данном случае лучше.
10 авг 08, 21:00    [6049713]     Ответить | Цитировать Сообщить модератору
 Re: CreateThread - проблемы выполнения  [new]
Где то там
Member

Откуда:
Сообщений: 452
Прошу прощения, не туда глянул.
10 авг 08, 21:06    [6049720]     Ответить | Цитировать Сообщить модератору
 Re: CreateThread - проблемы выполнения  [new]
Где то там
Member

Откуда:
Сообщений: 452
Просмотрел SDK, MSDN, а также исходники Delphi, но ничего применительно к моему случаю не нашёл. Если не сложно, напишите скелет кода, как это сделать.
10 авг 08, 21:34    [6049752]     Ответить | Цитировать Сообщить модератору
 Re: CreateThread - проблемы выполнения  [new]
C#C++
Member [заблокирован]

Откуда: Суровые северные земли
Сообщений: 2636
Где то там
Просмотрел SDK, MSDN, а также исходники Delphi, но ничего применительно к моему случаю не нашёл. Если не сложно, напишите скелет кода, как это сделать.

Вот, ваш код + event (вставки - желтым)
var
hPreLoad : HWND;
Dummy : DWORD;
hThread : HWND;
hEvent: HANDLE;

//---------------------------------------------------------

function PreLoadDialogProc(hWndDlg : HWND; Msg : Longint; wParam, lParam : Longint) : Boolean; stdcall;
begin
Result := False;
case Msg of
// не всегда выполняется
WM_INITDIALOG : hPreLoad := hWndDlg;
          SetEvent(hEvent); // переводим событие в сигнальное состояние
WM_COMMAND:
case LOWORD(wParam) of
IDOK,
IDCANCEL : EndDialog(hWndDlg, ord(True));
end;
end;
end;

//---------------------------------------------------------

procedure PreLoadDialogThread;
begin
DialogBox(hInstance, 'ID_PRELOADDLG', 0, @PreLoadDialogProc);
end;

//---------------------------------------------------------

begin
...
 //создаем событие в несигнальном состоянии
hEvent := CreateEvent(NIL, 0, 0, NIL);
hThread := CreateThread(NIL, 0, @PreLoadDialogThread, NIL, 0, Dummy);
... // выполняемая задача

 // ждем перехода события в сигнальное состояние, после чего убиваем за ненадобностью
WaitForSingleObject(hEvent, INFINITE);  CloseHandle(hEvent); hEvent := 0;
SendMessage(hPreLoad, WM_COMMAND, IDOK, 0); // Не всегда hPreload известен, иногда 0
hPreload := 0;
if hThread <> 0 then
begin
WaitForSingleObject(hThread, INFINITE);
CloseHandle(hThread);
hThread := 0;
end;
...
end;
10 авг 08, 22:37    [6049854]     Ответить | Цитировать Сообщить модератору
 Re: CreateThread - проблемы выполнения  [new]
Где то там
Member

Откуда:
Сообщений: 452
То-то я из исходников Delphi ничего не мог понять. Везде CreateEvent идет в паре с CreateThread, а из сказанного Вами ранее я понял, что от CreateThread нужно избавляться. Спасибо за помощь.
10 авг 08, 23:14    [6049943]     Ответить | Цитировать Сообщить модератору
 Re: CreateThread - проблемы выполнения  [new]
Dimitry Sibiryakov
Member

Откуда:
Сообщений: 50773

Где то там
я понял, что от CreateThread нужно избавляться.

Да мне вот тоже странно: зачем тут поток, если его окончания ждут по
WaitForSingleObject...

Posted via ActualForum NNTP Server 1.4

11 авг 08, 10:45    [6050883]     Ответить | Цитировать Сообщить модератору
 Re: CreateThread - проблемы выполнения  [new]
Где то там
Member

Откуда:
Сообщений: 452
Dimitry Sibiryakov

Где то там
я понял, что от CreateThread нужно избавляться.

Да мне вот тоже странно: зачем тут поток, если его окончания ждут по
WaitForSingleObject...
Posted via ActualForum NNTP Server 1.4


А разве в MSDN описано по другому?
11 авг 08, 11:08    [6051043]     Ответить | Цитировать Сообщить модератору
 Re: CreateThread - проблемы выполнения  [new]
Dimitry Sibiryakov
Member

Откуда:
Сообщений: 50773

Где то там
А разве в MSDN описано по другому?

Неужели в MSDN написано, что диалоги можно показывать только в отдельном
потоке?

Обычно завершения потоков вообще не ждут...

Posted via ActualForum NNTP Server 1.4

11 авг 08, 11:14    [6051079]     Ответить | Цитировать Сообщить модератору
 Re: CreateThread - проблемы выполнения  [new]
Где то там
Member

Откуда:
Сообщений: 452
Ну вообще так написано в MSDN и так делает Borland. И всем им не верить?
11 авг 08, 11:32    [6051203]     Ответить | Цитировать Сообщить модератору
 Re: CreateThread - проблемы выполнения  [new]
Dimitry Sibiryakov
Member

Откуда:
Сообщений: 50773

Где то там

так написано в MSDN и так делает Borland. И всем им не верить?

Точные цитаты, пожалуйста, в студию! Мне уже интересно, где это ты нашёл
у Борланда диалоги в потоках.

Posted via ActualForum NNTP Server 1.4

11 авг 08, 11:46    [6051296]     Ответить | Цитировать Сообщить модератору
 Re: CreateThread - проблемы выполнения  [new]
Гаджимурадов Рустам
Member

Откуда:
Сообщений: 61526

Dimitry Sibiryakov> Мне уже интересно, где это ты нашёл у Борланда диалоги в потоках.




Posted via ActualForum NNTP Server 1.4

11 авг 08, 11:51    [6051340]     Ответить | Цитировать Сообщить модератору
 Re: CreateThread - проблемы выполнения  [new]
Где то там
Member

Откуда:
Сообщений: 452
В исходники Delphi пожалуйста.
11 авг 08, 11:56    [6051376]     Ответить | Цитировать Сообщить модератору
 Re: CreateThread - проблемы выполнения  [new]
Dimitry Sibiryakov
Member

Откуда:
Сообщений: 50773

Где то там
В исходники Delphi пожалуйста.

Miln
"Url, url." - said Owl.

Posted via ActualForum NNTP Server 1.4

11 авг 08, 12:03    [6051412]     Ответить | Цитировать Сообщить модератору
 Re: CreateThread - проблемы выполнения  [new]
C#C++
Member [заблокирован]

Откуда: Суровые северные земли
Сообщений: 2636
Dimitry Sibiryakov
Да мне вот тоже странно: зачем тут поток, если его окончания ждут по
WaitForSingleObject...
Посмотри внимательно код:
hThread := CreateThread(NIL, 0, @PreLoadDialogThread, NIL, 0, Dummy);
... // выполняемая задача
Пока диалог на экране, в родительском потоке выполняются действия, после которых подается команда завершения диалога.

Как я понимаю, WaitForSingleObject(hThread, INFINITE); здесь используется только для того, чтоб вызвать CloseHandle(hThread); после завершения потока. Но это совсем необязательно, если закрыть hThread сразу, то с работающим потоком ничего не произойдёт (почему - см. Рихтер). Так что вполне можно сделать так:
CloseHandle(CreateThread(NIL, 0, @PreLoadDialogThread, NIL, 0, Dummy));
и убрать из кода все строки, где есть hThread
11 авг 08, 13:05    [6051792]     Ответить | Цитировать Сообщить модератору
 Re: CreateThread - проблемы выполнения  [new]
Где то там
Member

Откуда:
Сообщений: 452
C#C++

Пока диалог на экране, в родительском потоке выполняются действия, после которых подается команда завершения диалога.


Именно так.

C#C++

Как я понимаю, WaitForSingleObject(hThread, INFINITE); здесь используется только для того, чтоб вызвать CloseHandle(hThread); после завершения потока. Но это совсем необязательно, если закрыть hThread сразу, то с работающим потоком ничего не произойдёт (почему - см. Рихтер). Так что вполне можно сделать так:
CloseHandle(CreateThread(NIL, 0, @PreLoadDialogThread, NIL, 0, Dummy));
и убрать из кода все строки, где есть hThread


А поточнее? Имеется в виду это:

было
    hThread := CreateThread(NIL, 0, @PreLoadDialogThread, Pointer(hWndDlg), 0, Dummy);
стало
    CreateThread(NIL, 0, @PreLoadDialogThread, Pointer(hWndDlg), 0, Dummy);
11 авг 08, 13:17    [6051889]     Ответить | Цитировать Сообщить модератору
 Re: CreateThread - проблемы выполнения  [new]
C#C++
Member [заблокирован]

Откуда: Суровые северные земли
Сообщений: 2636
Где то там
А поточнее? Имеется в виду это:

было
    hThread := CreateThread(NIL, 0, @PreLoadDialogThread, Pointer(hWndDlg), 0, Dummy);
стало
    CreateThread(NIL, 0, @PreLoadDialogThread, Pointer(hWndDlg), 0, Dummy);
Имеется ввиду, что если не нужен дескриптор потока, то CloseHandle можно вызвать сразу после создания потока, на сам поток это никак не повлияет.
11 авг 08, 13:23    [6051924]     Ответить | Цитировать Сообщить модератору
Между сообщениями интервал более 1 года.
 Re: CreateThread - проблемы выполнения  [new]
Андрей Игоревич
Member

Откуда:
Сообщений: 319
Не хочется создавать тему ради пары дилетантских вопросов. Немного некромантии.

1. Как в Beginthread/Createthread корректно вызвать процедуру в главном потоке для синхронизации и обновления формы. Synchronize вроде как не вызвать, критическая секция не особо подходит. Сообщение? Событие? Ещё как-то?

2. Тут http://www.delphibasics.ru/BeginThread.php пишут
ThreadVar         // Мы должны позволить каждому потоку его собственные образцы
                  // переданной переменной записи
  msgPtr : ^TMsgRecord;
function ShowMsg(Parameter : Pointer) : Integer;
begin
  // Указываем указатель на переданные данные
  // Обратите внимание, что каждый поток имеет отдельную копию msgPtr
  msgPtr := Parameter;
...
Но ^TMsgRecord указатель на тот же участок памяти, отдельных копий же нет? То есть если дальше в главном потоке или в другом потоке что-то меняется, то меняется везде?

Почему не делают так?
ThreadVar  
  msgPtr : TMsgRecord;
function ShowMsg(Parameter : Pointer) : Integer;
begin
  msgPtr := TMsgRecord(Parameter^);

Или я просто не понял чего-то.

Сообщение было отредактировано: 31 июл 20, 02:52
31 июл 20, 02:54    [22175914]     Ответить | Цитировать Сообщить модератору
 Re: CreateThread - проблемы выполнения  [new]
wadman
Member

Откуда: Санкт-Петербург
Сообщений: 26714
Андрей Игоревич
Или я просто не понял чего-то.

Видимо

threadvar
x : integer;


declares an integer type variable that is private to each thread in the application, but global within each thread.
31 июл 20, 07:01    [22175918]     Ответить | Цитировать Сообщить модератору
 Re: CreateThread - проблемы выполнения  [new]
YuRock
Member

Откуда: Донецк
Сообщений: 4236
Андрей Игоревич
Но ^TMsgRecord указатель на тот же участок памяти, отдельных копий же нет?
Именно отдельные копии и будут для каждого потока при threadvar.
31 июл 20, 09:31    [22175939]     Ответить | Цитировать Сообщить модератору
 Re: CreateThread - проблемы выполнения  [new]
YuRock
Member

Откуда: Донецк
Сообщений: 4236
Андрей Игоревич
Как в Beginthread/Createthread корректно вызвать процедуру в главном потоке для синхронизации и обновления формы. Synchronize вроде как не вызвать
Так же, как и всегда - Send/PostMessage.
Если, не смотря на все проблемы, таки очень хочется Synchronize - можно написать TThread.Synchronize и передать туда чей-то метод.
31 июл 20, 09:35    [22175943]     Ответить | Цитировать Сообщить модератору
 Re: CreateThread - проблемы выполнения  [new]
DmSer
Member

Откуда: Пенза
Сообщений: 1158
YuRock
Андрей Игоревич
Как в Beginthread/Createthread корректно вызвать процедуру в главном потоке для синхронизации и обновления формы. Synchronize вроде как не вызвать
Так же, как и всегда - Send/PostMessage.
Если, не смотря на все проблемы, таки очень хочется Synchronize - можно написать TThread.Synchronize и передать туда чей-то метод.


Если Delphi современная, то можно передать анонимную процедуру.

Сообщение было отредактировано: 31 июл 20, 11:06
31 июл 20, 11:09    [22175996]     Ответить | Цитировать Сообщить модератору
 Re: CreateThread - проблемы выполнения  [new]
Андрей Игоревич
Member

Откуда:
Сообщений: 319
YuRock
Андрей Игоревич
Но ^TMsgRecord указатель на тот же участок памяти, отдельных копий же нет?
Именно отдельные копии и будут для каждого потока при threadvar.

Но ^TMsgRecord это же копия указателя, это не "Integer" и не полноценная переменная.

Ну просто для понимания тестовый пример:
+

type
  TData = record
    Data1:integer;
    Data2:extended;
    Data3:String[30];
  end;
var
    DataToThread:TData;
ThreadVar
    LocalData:^TData;
    MessageData:TMessageData;

function TestThread1(Prarameters:Pointer): Integer;
Begin
  Result := 0;
  LocalData := Prarameters;
  LocalData.Data1 := 4321;
  Sleep(200);
  //...
  Sendmessage (MainHandle, WM_DATA_UPDATE, 123, Integer(@MessageData) );
  EndThread(0);
End;

function TestThread2(Prarameters:Pointer): Integer;
Begin
  Result := 0;
  Sleep(100);
  LocalData := Prarameters;
  LocalData.Data1 := 1234;
  //...
  Sendmessage (MainHandle, WM_DATA_UPDATE, 321, Integer(@MessageData) );
  EndThread(0);
End;

procedure TForm1.Button1Click(Sender: TObject);
begin
   DataToTread.Data1 := 0;
   TreadHeandle1 := BeginThread  (nil, 0, @TestThread1, @DataToThread, 0, id1);
   TreadHeandle2 := BeginThread  (nil, 0, @TestThread2, @DataToThread, 0, id2);
   sleep(500);

   Memo1.Lines.Add(DataToTread.Data1.ToString);
   CloseHandle(TreadHeandle1);
   CloseHandle(TreadHeandle2);
end;


Суть кода выше:

По нажатии кнопки присваиваю глобальной переменной
DataToTread.Data1 := 0;

Передаю в поток 1 и 2 @DataToTread
Далее в потоке 1 "вроде как" локальной копии присваиваю значение
LocalData.Data1 := 4321;

В потоке 2 жду 100мс (дабы первый поток успел присвоить) и делаю
LocalData.Data1 := 1234;


В главном потоке жду пока всё закончиться sleep(500);
Вывожу глобальную переменную
Memo1.Lines.Add(DataToTread.Data1.ToString);

И вижу
Memo1
1234

Если бы там были локальные переменные, такого бы не произошло, осталось бы значение 0. Или я всё ещё продолжаю что-то не понимать.

Сообщение было отредактировано: 31 июл 20, 14:45
31 июл 20, 14:45    [22176220]     Ответить | Цитировать Сообщить модератору
Топик располагается на нескольких страницах: [1] 2   вперед  Ctrl      все
Все форумы / Delphi Ответить