Гость
Целевая тема:
Создать новую тему:
Автор:
Форумы / Delphi [игнор отключен] [закрыт для гостей] / CreateThread - проблемы выполнения / 25 сообщений из 42, страница 1 из 2
10.08.2008, 20:29
    #35480307
Где то там
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
CreateThread - проблемы выполнения
Вот кусок кода, с помощью которого я вызываю диалог на время выполнения операции. При инициализации, диалог отдает свой хэндл, чтобы потом его можно было закрыть. Но это происходит не всегда. В чём может быть причина?

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;
...
Рейтинг: 0 / 0
10.08.2008, 20:33
    #35480310
Где то там
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
CreateThread - проблемы выполнения
Жаль отредактировать нельзя, забыл выделить кодом.
...
Рейтинг: 0 / 0
10.08.2008, 20:41
    #35480317
C#C++
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
CreateThread - проблемы выполнения
Типичная ошибка многопоточного программирования ))
hPreLoad во втором потоке не успевает инициализироваться перед тем, как его использует SendMessage в первом.
Используйте Event (функции CreateEvent, SetEvent и WaitForSingleObject, см. хелп)

Кстати, PreLoadDialogThread должна быть функцией
function PreLoadDialogThread(p:DWORD):DWORD
...
Рейтинг: 0 / 0
10.08.2008, 21:00
    #35480328
Где то там
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
CreateThread - проблемы выполнения
авторКстати, PreLoadDialogThread должна быть функцией
function PreLoadDialogThread(p:DWORD):DWORD

Ну она и так функция. Нигде не сказано, что я не могу объявить её Boolean. А вот про Event нужно почитать, чем он в данном случае лучше.
...
Рейтинг: 0 / 0
10.08.2008, 21:06
    #35480330
Где то там
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
CreateThread - проблемы выполнения
Прошу прощения, не туда глянул.
...
Рейтинг: 0 / 0
10.08.2008, 21:34
    #35480337
Где то там
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
CreateThread - проблемы выполнения
Просмотрел SDK, MSDN, а также исходники Delphi, но ничего применительно к моему случаю не нашёл. Если не сложно, напишите скелет кода, как это сделать.
...
Рейтинг: 0 / 0
10.08.2008, 22:37
    #35480365
C#C++
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
CreateThread - проблемы выполнения
Где то тамПросмотрел SDK, MSDN, а также исходники Delphi, но ничего применительно к моему случаю не нашёл. Если не сложно, напишите скелет кода, как это сделать.
Вот, ваш код + event (вставки - желтым)
Код: plaintext
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.
 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 ;
...
Рейтинг: 0 / 0
10.08.2008, 23:14
    #35480380
Где то там
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
CreateThread - проблемы выполнения
То-то я из исходников Delphi ничего не мог понять. Везде CreateEvent идет в паре с CreateThread, а из сказанного Вами ранее я понял, что от CreateThread нужно избавляться. Спасибо за помощь.
...
Рейтинг: 0 / 0
11.08.2008, 10:45
    #35480735
Dimitry Sibiryakov
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
CreateThread - проблемы выполнения
Где то тамя понял, что от CreateThread нужно избавляться.

Да мне вот тоже странно: зачем тут поток, если его окончания ждут по
WaitForSingleObject...
Posted via ActualForum NNTP Server 1.4
...
Рейтинг: 0 / 0
11.08.2008, 11:08
    #35480782
Где то там
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
CreateThread - проблемы выполнения
Dimitry Sibiryakov
Где то тамя понял, что от CreateThread нужно избавляться.

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

А разве в MSDN описано по другому?
...
Рейтинг: 0 / 0
11.08.2008, 11:14
    #35480802
Dimitry Sibiryakov
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
CreateThread - проблемы выполнения
Где то тамА разве в MSDN описано по другому?

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

Обычно завершения потоков вообще не ждут...
Posted via ActualForum NNTP Server 1.4
...
Рейтинг: 0 / 0
11.08.2008, 11:32
    #35480844
Где то там
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
CreateThread - проблемы выполнения
Ну вообще так написано в MSDN и так делает Borland. И всем им не верить?
...
Рейтинг: 0 / 0
11.08.2008, 11:46
    #35480886
Dimitry Sibiryakov
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
CreateThread - проблемы выполнения
Где то там
так написано в MSDN и так делает Borland. И всем им не верить?

Точные цитаты, пожалуйста, в студию! Мне уже интересно, где это ты нашёл
у Борланда диалоги в потоках.
Posted via ActualForum NNTP Server 1.4
...
Рейтинг: 0 / 0
11.08.2008, 11:51
    #35480905
Гаджимурадов Рустам
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
CreateThread - проблемы выполнения
Dimitry Sibiryakov> Мне уже интересно, где это ты нашёл у Борланда диалоги в потоках.




Posted via ActualForum NNTP Server 1.4
...
Рейтинг: 0 / 0
11.08.2008, 11:56
    #35480920
Где то там
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
CreateThread - проблемы выполнения
В исходники Delphi пожалуйста.
...
Рейтинг: 0 / 0
11.08.2008, 12:03
    #35480941
Dimitry Sibiryakov
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
CreateThread - проблемы выполнения
Где то тамВ исходники Delphi пожалуйста.

Miln"Url, url." - said Owl.
Posted via ActualForum NNTP Server 1.4
...
Рейтинг: 0 / 0
11.08.2008, 13:05
    #35481098
C#C++
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
CreateThread - проблемы выполнения
Dimitry SibiryakovДа мне вот тоже странно: зачем тут поток, если его окончания ждут по
WaitForSingleObject...Посмотри внимательно код:
Код: plaintext
1.
2.
hThread := CreateThread( NIL ,  0 , @PreLoadDialogThread,  NIL ,  0 , Dummy);
...  // выполняемая задача 
Пока диалог на экране, в родительском потоке выполняются действия, после которых подается команда завершения диалога.

Как я понимаю, WaitForSingleObject(hThread, INFINITE); здесь используется только для того, чтоб вызвать CloseHandle(hThread); после завершения потока. Но это совсем необязательно, если закрыть hThread сразу, то с работающим потоком ничего не произойдёт (почему - см. Рихтер). Так что вполне можно сделать так:
Код: plaintext
1.
CloseHandle(CreateThread( NIL ,  0 , @PreLoadDialogThread,  NIL ,  0 , Dummy));
и убрать из кода все строки, где есть hThread
...
Рейтинг: 0 / 0
11.08.2008, 13:17
    #35481138
Где то там
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
CreateThread - проблемы выполнения
C#C++
Пока диалог на экране, в родительском потоке выполняются действия, после которых подается команда завершения диалога.

Именно так.

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

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

было
Код: plaintext
1.
    hThread := CreateThread( NIL ,  0 , @PreLoadDialogThread, Pointer(hWndDlg),  0 , Dummy);
стало
Код: plaintext
1.
    CreateThread( NIL ,  0 , @PreLoadDialogThread, Pointer(hWndDlg),  0 , Dummy);
...
Рейтинг: 0 / 0
11.08.2008, 13:23
    #35481156
C#C++
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
CreateThread - проблемы выполнения
Где то тамА поточнее? Имеется в виду это:

было
Код: plaintext
1.
    hThread := CreateThread( NIL ,  0 , @PreLoadDialogThread, Pointer(hWndDlg),  0 , Dummy);
стало
Код: plaintext
1.
    CreateThread( NIL ,  0 , @PreLoadDialogThread, Pointer(hWndDlg),  0 , Dummy);
Имеется ввиду, что если не нужен дескриптор потока, то CloseHandle можно вызвать сразу после создания потока, на сам поток это никак не повлияет.
...
Рейтинг: 0 / 0
Период между сообщениями больше года.
31.07.2020, 02:54
    #39985454
CreateThread - проблемы выполнения
Не хочется создавать тему ради пары дилетантских вопросов. Немного некромантии.

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

2. Тут http://www.delphibasics.ru/BeginThread.php пишут
Код: pascal
1.
2.
3.
4.
5.
6.
7.
8.
9.
ThreadVar         // Мы должны позволить каждому потоку его собственные образцы
                  // переданной переменной записи
  msgPtr : ^TMsgRecord;
function ShowMsg(Parameter : Pointer) : Integer;
begin
  // Указываем указатель на переданные данные
  // Обратите внимание, что каждый поток имеет отдельную копию msgPtr
  msgPtr := Parameter;
...

Но ^TMsgRecord указатель на тот же участок памяти, отдельных копий же нет? То есть если дальше в главном потоке или в другом потоке что-то меняется, то меняется везде?

Почему не делают так?
Код: pascal
1.
2.
3.
4.
5.
ThreadVar  
  msgPtr : TMsgRecord;
function ShowMsg(Parameter : Pointer) : Integer;
begin
  msgPtr := TMsgRecord(Parameter^);


Или я просто не понял чего-то.
...
Рейтинг: 0 / 0
31.07.2020, 07:01
    #39985456
wadman
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
CreateThread - проблемы выполнения
Андрей Игоревич
Или я просто не понял чего-то.

Видимо
Код: plaintext
1.
2.
3.
 [code=pascal]
threadvar
x : integer;



declares an integer type variable that is private to each thread in the application, but global within each thread.
...
Рейтинг: 0 / 0
31.07.2020, 09:31
    #39985468
YuRock
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
CreateThread - проблемы выполнения
Андрей Игоревич
Но ^TMsgRecord указатель на тот же участок памяти, отдельных копий же нет?
Именно отдельные копии и будут для каждого потока при threadvar.
...
Рейтинг: 0 / 0
31.07.2020, 09:35
    #39985469
YuRock
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
CreateThread - проблемы выполнения
Андрей Игоревич
Как в Beginthread/Createthread корректно вызвать процедуру в главном потоке для синхронизации и обновления формы. Synchronize вроде как не вызвать
Так же, как и всегда - Send/PostMessage.
Если, не смотря на все проблемы, таки очень хочется Synchronize - можно написать TThread.Synchronize и передать туда чей-то метод.
...
Рейтинг: 0 / 0
31.07.2020, 11:09
    #39985496
DmSer
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
CreateThread - проблемы выполнения
YuRock
Андрей Игоревич
Как в Beginthread/Createthread корректно вызвать процедуру в главном потоке для синхронизации и обновления формы. Synchronize вроде как не вызвать
Так же, как и всегда - Send/PostMessage.
Если, не смотря на все проблемы, таки очень хочется Synchronize - можно написать TThread.Synchronize и передать туда чей-то метод.


Если Delphi современная, то можно передать анонимную процедуру.
...
Рейтинг: 0 / 0
31.07.2020, 14:45
    #39985584
CreateThread - проблемы выполнения
YuRock
Андрей Игоревич
Но ^TMsgRecord указатель на тот же участок памяти, отдельных копий же нет?
Именно отдельные копии и будут для каждого потока при threadvar.

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

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

Код: 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.
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;



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

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


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


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



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


И вижу
Memo11234
Если бы там были локальные переменные, такого бы не произошло, осталось бы значение 0. Или я всё ещё продолжаю что-то не понимать.
...
Рейтинг: 0 / 0
Форумы / Delphi [игнор отключен] [закрыт для гостей] / CreateThread - проблемы выполнения / 25 сообщений из 42, страница 1 из 2
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


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