BeginThread — Функция Delphi


beginthread

04.11.2010, 12:41

Создать поток, реализованный в модуле, через beginthread
Народ, помогите.Нужно вызвать поток через функцию.

Из запущенного с помощью функции BeginThread потока нужно вывести текст в RichEdit
Из запущенного с помощью функции BeginThread потока нужно вывести текст в RichEdit, как это сделать.

beginthread и параметр
unit Unit1; interface uses Forms, Dialogs, Windows, SysUtils, Classes, Controls.

Или воспользуйтесь поиском по форуму:

04.11.2010, 12:52 2
04.11.2010, 12:56 [ТС] 3
04.11.2010, 13:11 4

отличия BeginThread:
1. Это не API функция венды.
2. Код функции ниже:

BeginThread — Функция Delphi

You can have more than one thread — each thread is another, independent variation on the main line of code execution.

When calling a BeginThread function, you are creating a new thread which executes the specified ThreadFunc function. This is a function with Param as its singles Pointer argument. The thread runs until this function ends.

When the thread is created, it returns a thread id in the returned integer. When the thread returns, you should call the CloseThread Windows function to free up resources.

Each thread has the same access to the Unit data as the main line of execution. Much care must be taken when accessing data shared between threads.

To provide data unique variable instances to each thread, use a ThreadVar definition in the Unit, as in the example.

You can pass data to each thread via the Param pointer, as in the example.

BeginThread — Функция Delphi

Spawns a separate thread of execution.

Use this routine or a TThread object to spawn separate threads of execution. BeginThread spawns a new thread of execution and sets the global IsMultiThread variable, thereby making the heap thread-safe.

ThreadFunc is the thread function. This is the code that executes in the new thread of execution. ThreadFunc should handle all of its own exceptions. However, because BeginThread sets up an execution frame, the system’s default exception handler will catch any exceptions that escape ThreadFunc.

Parameter points to a single 32-bit parameter that is passed, uninterpreted, to ThreadFunc.

ThreadId returns the unique identifier for the new thread. This ID appears in the Thread Status box of the debugger.

SecurityAttributes is a pointer to a Windows SecurityAttributes record (structure). For details on security attributes, see the Microsoft documentation.

StackSize is the size of the stack reserved for the new thread when CreationFlags includes STACK_SIZE_IS_A_RESERVATION. Otherwise, this parameter is ignored.

CreationFlags is a set of bits or’ed together that are drawn from the following:

On Windows, BeginThread returns the Windows thread handle. A return value of 0 indicates failure.

Attribute is a structure containing information about the thread such as its priority, its schedule policy, and its stack size.

On Linux, Begin Thread returns 0 if the thread is successfully spawned, an error code otherwise.

BeginThread — Функция Delphi

244 просмотра

1 ответ

351 Репутация автора

при использовании BeginThread в Delphi XE3 функция блокируется. Это почему?

Я попытался создать минимальную версию моей проблемы ниже. Если можно нажать кнопку 2, при нажатии кнопки btn1 заголовок btn1 должен измениться на «nooo». если нажата btn2, заголовок btn1 меняется на «yesss».

Когда нажата btn1, я также запускаю поток, используя BeginThread, который зацикливается навсегда.

Проблема в том, что btn1.Caption: = ‘nooo’; никогда не возвращается, так как блоки BeginThread. Крикнул я дошел до btn1.Caption: = ‘nooo’;

Ответы (1)

7 плюса

148271 Репутация автора

Выражение Pointer(test) вызывает, test() а затем вводит результат в Pointer . Поскольку test() никогда не возвращается, нет результата для приведения и, следовательно, нет значения для передачи BeginThread() . BeginThread() сам не блокирует; это никогда не вызывается во-первых.

Третий аргумент BeginThread() не относится к типу Pointer ; это тип TThreadFunc , который является автономной (не-членской) функцией, которая получает один Pointer аргумент и возвращает Integer . Ваш TForm1.test() метод не подходит, потому что это не отдельная функция.

Создайте test() автономную функцию и затем передайте ее напрямую BeginThread() (без приведения типов или @ оператора):

BeginThread delphi blocking function

if using BeginThread in Delphi XE3 the function is blocked. Why is that?

I have tried to create the minimal version of my problem below. Where 2 buttom can be pressed, if presseing button btn1 the caption of btn1 should change to ‘nooo’. if btn2 is pressed btn1 caption change to ‘yesss’.

When btn1 is pressed I also start a thread using BeginThread that loops forever.

The problem is then, btn1.Caption := ‘nooo’; is never reased since BeginThread blocks. Shouled I reach btn1.Caption := ‘nooo’;

1 Answer 1

The expression Pointer(test) calls test() and then type-casts the result to a Pointer . Since test() never returns, there’s no result to cast, and thus no value to pass to BeginThread() . BeginThread() itself doesn’t block; it never gets called in the first place.

The third argument to BeginThread() is not of type Pointer ; it is of type TThreadFunc , which is a standalone (non-member) function that receives one Pointer argument and returns an Integer . Your TForm1.test() method doesn’t qualify, because it’s not a standalone function.

Make test() be a standalone function, and then pass it directly to BeginThread() (without any type-casting or @ operator):

Not the answer you’re looking for? Browse other questions tagged delphi or ask your own question.

Hot Network Questions

Subscribe to RSS

To subscribe to this RSS feed, copy and paste this URL into your RSS reader.

site design / logo © 2020 Stack Exchange Inc; user contributions licensed under cc by-sa 4.0 with attribution required. rev 2020.11.11.35399

BeginThread — Функция Delphi

Опубликовано: Октябрь 2020

Самая актуальная документация по Visual Studio 2020: Документация по Visual Studio 2020.

Параметры

start_address
Начальный адрес процедуры, который начинает выполнение нового потока. Для _beginthread соглашение о вызовах — это либо __cdecl (для машинного кода), либо __clrcall (для управляемого кода); для _beginthreadex это либо __stdcall (для машинного кода), либо __clrcall (для управляемого кода).

stack_size
Размер стека нового потока или 0.

arglist
Список аргументов, который должен быть передан новому потоку, или NULL.

Security
Указатель на структуру SECURITY_ATTRIBUTES определяет, может ли возвращаемый дескриптор быть унаследован дочерними процессами. Если Security равен NULL, дескриптор не наследуется. Должно быть NULL для приложений Windows 95.

initflag
Флаги, управляющие начальным состоянием нового потока. Задайте для параметра initflag флаг 0 , чтобы выполнять запуск немедленно, или флаг CREATE_SUSPENDED , чтобы создать поток в приостановленном состоянии. Для выполнения потока используйте функцию ResumeThread . Задайте для параметра initflag флаг STACK_SIZE_PARAM_IS_A_RESERVATION , чтобы использовать stack_size в качестве начального зарезервированного размера стека (в байтах); если этот флаг не указан, stack_size задает выделенный размер.

thrdaddr
Указывает на 32-разрядную переменную, которая получает идентификатор потока. Если равно NULL, оно не используется.

В случае успеха каждая из этих функций возвращает дескриптор во вновь созданный поток; однако если вновь созданный поток выполняет выход слишком быстро, _beginthread может не возвращать допустимый дескриптор. (См. обсуждение в разделе «Заметки».) При возникновении ошибки _beginthread возвращает -1L, а параметр errno имеет значение EAGAIN , если слишком много потоков, значение EINVAL , если аргумент является недопустимым или размер стека неверен, либо значение EACCES , если недостаточно ресурсов (например, памяти). При возникновении ошибки _beginthreadex возвращает 0, а errno и _doserrno заданы.

Если startaddress имеет значение NULL, вызывается обработчик недопустимых параметров, как описано в разделе Parameter Validation. Если продолжение выполнения разрешено, эти функции устанавливают для errno значение EINVAL и возвращают -1.

Дополнительные сведения об этих и других кодах возврата см. в разделе errno _doserrno, _sys_errlist и _sys_nerr.

Дополнительные сведения о uintptr_t см. в разделе Standard Types.

Функция _beginthread создает поток, который начинает выполнение процедуры в start_address . В процедуре start_address необходимо использовать __cdecl (для машинного кода) или соглашение о вызовах __clrcall (для управляемого кода); там не должно быть возвращаемого значения. При возврате потока из этой процедуры он завершается автоматически. Дополнительные сведения о потоках см. в разделе поддержка многопоточности для устаревшего кода (Visual C++).

_beginthreadex напоминает Win32 CreateThread API более чем _beginthread does. _beginthreadex имеет следующие отличия от _beginthread :

_beginthreadex имеет три дополнительных параметра: initflag , security и threadaddr . Новый поток можно создать в приостановленном состоянии (с заданной безопасностью), а доступ к нему можно осуществлять с помощью thrdaddr , который является идентификатором потока.

Процедура в start_address , передаваемая атрибуту _beginthreadex , должна использовать __stdcall (для машинного кода) или соглашение о вызовах __clrcall (для управляемого кода) и должна возвращать код завершения потока.

_beginthreadex возвращает при ошибке 0, а не -1L.

Поток, созданный с помощью _beginthreadex , завершается вызовом метода _endthreadex.

Функция _beginthreadex обеспечивает большую подконтрольность создания потока, чем _beginthread . Функция _endthreadex также является более гибкой. Например, с помощью _beginthreadex можно использовать сведения о безопасности, задавать исходное состояние потока (выполняемого или приостановленного) и получить идентификатор только что созданного потока. Можно также использовать дескриптор потока, возвращаемого методом _beginthreadex , с помощью функций синхронизации API-интерфейса, что невозможно в случае с _beginthread .

Безопаснее использовать _beginthreadex , чем _beginthread . Если поток, созданный _beginthread , выполняет выход быстро, маркер, возвращаемый вызывающему объекту _beginthread , может быть недопустим или указывать на другой поток. Однако маркер, который возвращается _beginthreadex , должен быть закрыт вызывающим объектом _beginthreadex , поэтому это однозначно допустимый маркер, если _beginthreadex не возвращает ошибку.

Можно вызвать _endthread или _endthreadex , чтобы явно завершить поток; однако _endthread или _endthreadex вызывается автоматически при возврате потока из процедуры, что передается в качестве параметра. Остановка потока вызовом метода _endthread или _endthreadex помогает обеспечить правильное восстановление ресурсов, выделяемых для потока.

_endthread автоматически закрывает дескриптор потока, тогда как _endthreadex этого не делает. Поэтому при использовании _beginthread и _endthread не следует явно закрывать дескриптор потока вызовом API Win32 CloseHandle . Это поведение отличается от функции API Win32 ExitThread .

Для исполняемого файла, связанного с Libcmt.lib, не следует вызывать функцию API Win32 ExitThread , чтобы не помешать системе времени выполнения освобождать выделенные ресурсы. _endthread и _endthreadex освобождают выделенные ресурсы потока и затем вызывают метод ExitThread .

Операционная система обрабатывает выделение стека, если _beginthread или _beginthreadex вызываются; не следует передавать адрес стека потоков любой из этих функций. Кроме того, аргумент stack_size может быть 0, в случае чего операционная система использует то же значение, что и стек, указанный для основного потока.

arglist — это параметр для передачи только что созданному потоку. Как правило, это адрес элемента данных, например строки символов. arglist может иметь значение NULL, если он не является обязательным, но _beginthread и _beginthreadex должны получить какое-либо значение для передачи новому потоку. Все потоки завершаются, если какой-либо поток вызывает метод abort , exit , _exit или ExitProcess .

Языковой стандарт нового потока наследуется от родительского потока. Если языковой стандарт отдельного потока включен при вызове _configthreadlocale (глобально или только для новых потоков), поток может изменить его языковой стандарт независимо от родительского элемента, вызвав метод setlocale или _wsetlocale . Для получения дополнительной информации см. Locale.

Для смешанного и чистого кода _beginthread и _beginthreadex имеют две перегруженные версии — одна имеет указатель функции соглашения о вызовах неуправляемого кода, а другой получает указатель функции __clrcall . Первый перегруженный метод не является безопасным для домена приложения и никогда таковым не будет. При записи смешанного или чистого кода нужно убедиться, что новый поток входит в правильный домен приложений, прежде чем осуществит доступ к управляемым ресурсам. Можно сделать это, например, с помощью функция call_in_appdomain. Вторая перегрузка является доменобезопасной; только что созданный поток всегда завершается в домене приложения вызывающего объекта _beginthread или _beginthreadex .

Примечание

Дополнительные сведения о совместимости см. в разделе Compatibility.

_beginthread, _beginthreadex _beginthread, _beginthreadex

Создает поток. Creates a thread.

Синтаксис Syntax

Параметры Parameters

start_address start_address
Начальный адрес процедуры, который начинает выполнение нового потока. Start address of a routine that begins execution of a new thread. Для _beginthreadсоглашением о вызовах является либо __cdecl (для машинного кода), либо __clrcall (для управляемого кода). для _beginthreadexэто либо __stdcall (для машинного кода), либо __clrcall (для управляемого кода). For _beginthread, the calling convention is either __cdecl (for native code) or __clrcall (for managed code); for _beginthreadex, it is either __stdcall (for native code) or __clrcall (for managed code).

stack_size stack_size
Размер стека нового потока или 0. Stack size for a new thread, or 0.

arglist arglist
Список аргументов, передаваемый в новый поток, или значение NULL. Argument list to be passed to a new thread, or NULL.

Безопасность Security
Указатель на структуру SECURITY_ATTRIBUTES определяет, может ли возвращаемый дескриптор быть унаследован дочерними процессами. Pointer to a SECURITY_ATTRIBUTES structure that determines whether the returned handle can be inherited by child processes. Если Безопасность имеет значение NULL, маркер не может быть унаследован. If Security is NULL, the handle cannot be inherited. Для приложений Windows 95 значение должно быть равно NULL . Must be NULL for Windows 95 applications.

инитфлаг initflag
Флаги, управляющие начальным состоянием нового потока. Flags that control the initial state of a new thread. Задайте для инитфлаг значение 0 для немедленного выполнения или CREATE_SUSPENDED , чтобы создать поток в приостановленном состоянии. Используйте ресумесреад для выполнения потока. Set initflag to 0 to run immediately, or to CREATE_SUSPENDED to create the thread in a suspended state; use ResumeThread to execute the thread. Установите флаг инитфлаг в STACK_SIZE_PARAM_IS_A_RESERVATION , чтобы использовать STACK_SIZE в качестве начального резервного размера стека в байтах; Если этот флаг не указан, stack_size задает размер фиксации. Set initflag to STACK_SIZE_PARAM_IS_A_RESERVATION flag to use stack_size as the initial reserve size of the stack in bytes; if this flag is not specified, stack_size specifies the commit size.

срдаддр thrdaddr
Указывает на 32-разрядную переменную, которая получает идентификатор потока. Points to a 32-bit variable that receives the thread identifier. Если он равен null, он не используется. If it’s NULL, it’s not used.

Возвращаемое значение Return Value

В случае успеха каждая из этих функций возвращает маркер вновь созданного потока. Однако если вновь созданный поток завершается слишком быстро, _beginthread может не возвращать допустимый маркер. If successful, each of these functions returns a handle to the newly created thread; however, if the newly created thread exits too quickly, _beginthread might not return a valid handle. (См. обсуждение в разделе «Заметки».) При возникновении ошибки _beginthread возвращает значение-1L, а для свойства «переводится» на » еагаин «, если слишком много потоков, в еинвал , если аргумент является недопустимым или размер стека неверен, или на еакцес , если недостаточно ресурсов ( например память). (See the discussion in the Remarks section.) On an error, _beginthread returns -1L, and errno is set to EAGAIN if there are too many threads, to EINVAL if the argument is invalid or the stack size is incorrect, or to EACCES if there are insufficient resources (such as memory). При возникновении ошибки _beginthreadex возвращает 0, а задаются значения «T0 » и « _doserrno «. On an error, _beginthreadex returns 0, and errno and _doserrno are set.

Если start_address имеет значение NULL, вызывается обработчик недопустимых параметров, как описано в разделе Проверка параметров. If start_address is NULL, the invalid parameter handler is invoked, as described in Parameter Validation. Если выполнение может быть продолжено, эти функции устанавливают значение еинвал и возвращают-1. If execution is allowed to continue, these functions set errno to EINVAL and return -1.

Дополнительные сведения об этих и других кодах возврата см. в разделе errno, _doserrno, _sys_errlist и _sys_nerr. For more information about these and other return codes, see errno, _doserrno, _sys_errlist, and _sys_nerr.

Дополнительные сведения о uintptr_tсм. в разделе стандартные типы. For more information about uintptr_t, see Standard Types.

Примечания Remarks

Функция _beginthread создает поток, который начинает выполнение процедуры в start_address. The _beginthread function creates a thread that begins execution of a routine at start_address. Подпрограмма на start_address должна использовать соглашение о вызовах __cdecl (для машинного кода) или __clrcall (для управляемого кода) и не должно иметь возвращаемого значения. The routine at start_address must use the __cdecl (for native code) or __clrcall (for managed code) calling convention and should have no return value. При возврате потока из этой процедуры он завершается автоматически. When the thread returns from that routine, it is terminated automatically. Дополнительные сведения о потоках см. в разделе Поддержка многопоточности для устаревшего кода (Visual C++). For more information about threads, see Multithreading Support for Older Code (Visual C++).

_beginthreadex похож на API-интерфейс Win32 CreateThread более тесно, чем _beginthread . _beginthreadex resembles the Win32 CreateThread API more closely than _beginthread does. _beginthreadex отличается от _beginthread следующими способами. _beginthreadex differs from _beginthread in the following ways:

_beginthreadex имеет три дополнительных параметра: инитфлаг, Securityи среададдр. _beginthreadex has three additional parameters: initflag, Security, and threadaddr. Новый поток может быть создан в приостановленном состоянии с заданной безопасностью и доступен с помощью срдаддр, который является идентификатором потока. The new thread can be created in a suspended state, with a specified security, and can be accessed by using thrdaddr, which is the thread identifier.

Подпрограмма на start_address , которая передается в _beginthreadex , должна использовать соглашение о вызовах __stdcall (для машинного кода) или __clrcall (для управляемого кода) и должно возвращать код выхода потока. The routine at start_address that’s passed to _beginthreadex must use the __stdcall (for native code) or __clrcall (for managed code) calling convention and must return a thread exit code.

_beginthreadex возвращает 0 в случае сбоя, а не-1L. _beginthreadex returns 0 on failure, rather than -1L.

Поток, созданный с помощью _beginthreadex , завершается вызовом _endthreadex. A thread that’s created by using _beginthreadex is terminated by a call to _endthreadex.

Функция _beginthreadex обеспечивает более полный контроль над созданием потока, чем _beginthread . The _beginthreadex function gives you more control over how the thread is created than _beginthread does. Функция _endthreadex также является более гибкой. The _endthreadex function is also more flexible. Например, с помощью _beginthreadexможно использовать сведения о безопасности, установить начальное состояние потока (выполняется или приостановлено) и получить идентификатор потока только что созданного потока. For example, with _beginthreadex, you can use security information, set the initial state of the thread (running or suspended), and get the thread identifier of the newly created thread. Кроме того, можно использовать обработчик, возвращаемый функцией _beginthreadex , с API-интерфейсами синхронизации, которые невозможно выполнить с помощью _beginthread. You can also use the thread handle that’s returned by _beginthreadex with the synchronization APIs, which you cannot do with _beginthread.

Более безопасно использовать _beginthreadex , чем _beginthread. It’s safer to use _beginthreadex than _beginthread. Если поток, созданный с помощью _beginthread , быстро завершает работу, то маркер, возвращаемый вызывающему объекту _beginthread , может быть недопустимым или указывать на другой поток. If the thread that’s generated by _beginthread exits quickly, the handle that’s returned to the caller of _beginthread might be invalid or point to another thread. Однако маркер, возвращаемый _beginthreadex , должен быть закрыт вызывающим объектом _beginthreadex, поэтому он гарантированно должен быть допустимым, если _beginthreadex не возвращал ошибку. However, the handle that’s returned by _beginthreadex has to be closed by the caller of _beginthreadex, so it is guaranteed to be a valid handle if _beginthreadex did not return an error.

Можно явно вызвать _endthread или _endthreadex , чтобы завершить поток. Однако _endthread или _endthreadex вызывается автоматически, когда поток возвращается из подпрограммы, передаваемой в качестве параметра. You can call _endthread or _endthreadex explicitly to terminate a thread; however, _endthread or _endthreadex is called automatically when the thread returns from the routine that’s passed as a parameter. Завершение потока с вызовом _endthread или _endthreadex помогает обеспечить правильное восстановление ресурсов, выделенных для потока. Terminating a thread with a call to _endthread or _endthreadex helps ensure correct recovery of resources that are allocated for the thread.

_endthread автоматически закрывает обработчик потока, а _endthreadex — нет. _endthread automatically closes the thread handle, whereas _endthreadex does not. Поэтому при использовании _beginthread и _endthreadне следует явно закрывать обработчик потока, вызывая API-интерфейс Win32 CloseHandle . Therefore, when you use _beginthread and _endthread, do not explicitly close the thread handle by calling the Win32 CloseHandle API. Это поведение отличается от функции API Win32 ExitThread . This behavior differs from the Win32 ExitThread API.

Для исполняемого файла, связанного с LIBCMT. lib, не следует вызывать API Win32 ExitThread , чтобы не предотвратить освобождение выделенных ресурсов системой времени выполнения. For an executable file linked with Libcmt.lib, do not call the Win32 ExitThread API so that you don’t prevent the run-time system from reclaiming allocated resources. _endthread и _endthreadex освобождают выделенные ресурсы потока и затем вызывают ExitThread. _endthread and _endthreadex reclaim allocated thread resources and then call ExitThread.

Операционная система обрабатывает выделение стека при вызове _beginthread или _beginthreadex ; не нужно передавать адрес стека потока ни одной из этих функций. The operating system handles the allocation of the stack when either _beginthread or _beginthreadex is called; you don’t have to pass the address of the thread stack to either of these functions. Кроме того, аргумент stack_size может быть равен 0, в этом случае операционная система использует то же значение, что и стек, указанный для основного потока. In addition, the stack_size argument can be 0, in which case the operating system uses the same value as the stack that’s specified for the main thread.

arglist — это параметр, передаваемый только что созданному потоку. arglist is a parameter to be passed to the newly created thread. Как правило, это адрес элемента данных, например строки символов. Typically, it is the address of a data item, such as a character string. arglist может иметь значение NULL , если это не требуется, но _beginthread и _beginthreadex должны иметь какое-либо значение для передачи в новый поток. arglist can be NULL if it is not needed, but _beginthread and _beginthreadex must be given some value to pass to the new thread. Все потоки завершаются, если какой бы то ни было поток вызывал прерывания, Exit, _exitили ExitProcess. All threads are terminated if any thread calls abort, exit, _exit, or ExitProcess.

Языковой стандарт для нового потока инициализируется с использованием сведений о глобальном текущем языковом стандарте для каждого процесса. The locale of the new thread is initialized by using the per-process global current locale info. Если языковой стандарт для каждого потока включен с помощью вызова _configthreadlocale (либо глобально, либо только для новых потоков), поток может изменить свой языковой стандарт независимо от других потоков, вызвав setlocale или _wsetlocale. If per-thread locale is enabled by a call to _configthreadlocale (either globally or for new threads only), the thread can change its locale independently from other threads by calling setlocale or _wsetlocale. Потоки, у которых нет установленного флага локали для каждого потока, могут влиять на сведения о языковых стандартах во всех других потоках, которые также не имеют установленного флага локали для каждого потока, а также всех вновь создаваемых потоков. Threads that don’t have the per-thread locale flag set can affect the locale info in all other threads that also don’t have the per-thread locale flag set, as well as all newly-created threads. Для получения дополнительной информации см. Locale. For more information, see Locale.

Для кода /CLR _beginthread и _beginthreadex имеют две перегрузки. For /clr code, _beginthread and _beginthreadex each have two overloads. Один принимает собственный указатель функции соглашения о вызовах, а другой принимает указатель на функцию __clrcall . One takes a native calling-convention function pointer, and the other takes a __clrcall function pointer. Первый перегруженный метод не является безопасным для домена приложения и никогда таковым не будет. The first overload is not application domain-safe and never will be. При написании кода /CLR необходимо убедиться, что новый поток входит в правильный домен приложения, прежде чем он будет получать доступ к управляемым ресурсам. If you are writing /clr code you must ensure that the new thread enters the correct application domain before it accesses managed resources. Это можно сделать, например, с помощью функции call_in_appdomain. You can do this, for example, by using call_in_appdomain Function. Вторая перегрузка — это Доменная безопасность приложения; вновь созданный поток всегда будет находиться в домене приложения вызывающего объекта _beginthread или _beginthreadex. The second overload is application domain-safe; the newly created thread will always end up in the application domain of the caller of _beginthread or _beginthreadex.

Требования Requirements

Подпрограмма Обязательный заголовок
_beginthread
_beginthreadex

Дополнительные сведения о совместимости см. в разделе Совместимость. For more compatibility information, see Compatibility.

Библиотеки Libraries

Только многопоточные версии библиотек времени выполнения языка C . Multithreaded versions of the C run-time libraries only.

Чтобы использовать _beginthread или _beginthreadex, приложение должно создать связь с одной из многопоточных библиотек времени выполнения C. To use _beginthread or _beginthreadex, the application must link with one of the multithreaded C run-time libraries.

Пример Example

В следующем примере используются _beginthread и _endthread. The following example uses _beginthread and _endthread.

Чтобы закрыть приложение-пример, нажмите любую клавишу. Press any key to end the sample application.

Пример Example

В следующем примере кода показано, как можно использовать обработчик потока, возвращаемый функцией _beginthreadex , с помощью WaitForSingleObjectAPI синхронизации. The following sample code demonstrates how you can use the thread handle that’s returned by _beginthreadex with the synchronization API WaitForSingleObject. Основной поток ожидает завершения другого потока, прежде чем продолжить. The main thread waits for the second thread to terminate before it continues. Когда второй поток вызывает _endthreadex, он приводит к тому, что его объект потока переходит в сигнальное состояние. When the second thread calls _endthreadex, it causes its thread object to go to the signaled state. Это позволяет продолжить выполнение основного потока. This allows the primary thread to continue running. Это невозможно сделать с помощью _beginthread и _endthread, так как _endthread вызывает CloseHandle, который уничтожает объект потока, прежде чем его можно будет установить в сигнальное состояние. This cannot be done with _beginthread and _endthread, because _endthread calls CloseHandle, which destroys the thread object before it can be set to the signaled state.

BeginThread — Функция Delphi

Пытаюсь сделать поток такого типа.
Но при выходе (ThreadTerminate->CloseHandle)всегда образуется утечка памяти.
Как правильно высвободить поток в этом случае?
Код внизу.

Это просто пример. Я просто изучаю эту структуру. Bот нашел пример .
Kритикал сектион сам прикрутил тоже для проверки.
Пока не изучу это чудо себе в программу добавлять небуду.
Сам пример с утечкой памяти.

Интересно, как можно вот так на шару юзать функции TerminateThread и SuspendThread, не прочитав о том, чем чревато их использование?! В данном случае, утечка памяти это мелочь, по сравнению с другими возможными последствиями, например со сбоем структуры динамической памяти со всеми вытекающими отсюда EInvalidPointer и EAccessViolation, или с глобальным зависоном всего приложения (в старших версиях дельфи с FastMM это маловероятно, но в D7 очень даже возможно, если прервать или усыпить поток на выделении строки в IntToStr).

Резюме: TerminateThread можно использовать только в аварийных ситуациях, когда нет других способов завершить поток — в этом случае и на утечку памяти можно закрыть глаза. Вызов SuspendThread из другого потока используется также только в особых случаях, например, в отладчиках, вирях\антивирях и прочих хакерских штучках. А в обычных программах SuspendThread либо вообще не используют, либо используют в самом потоке, который должен уснуть по команде извне

Объект TThread

Фактически Delphi инкапсулирует в объекте Object Pascal TThread объект потока API. Хотя класс TThread инкапсулирует практически все важнейшие функции объек та потока API в одном едином объекте, возможны ситуации, когда придется непо средственно обращаться к функциям API. Чаще всего это будет связано с необходимо стью синхронизации потоков. В настоящем разделе обсудим работу объекта TThread и его применение в создаваемых приложениях.

Принципы работы объекта TThread

Класс TThread находится в модуле Classes и определен следующим образом:

TThread = class private

// ** FThreadID не соответствует THandle в Linux **

FTerminated: Boolean;FSuspended: Boolean; FFreeOnTerminate: Boolean; FFinished: Boolean; FReturnValue: Integer; FOnTerminate: TNotifyEvent; FMethod: TThreadMethod; FSynchronizeException: TObject; FFatalException: TObject;

procedure CheckThreadError(ErrCode: Integer); overload; procedure CheckThreadError(Success: Boolean); overload; procedure CallOnTerminate;

function GetPriority: TThreadPriority;

procedure SetPriority(Value: TThreadPriority);

procedure SetSuspended(Value: Boolean);

// ** В Linux значение приоритета (Priority) имеет тип Integer

function GetPriority: Integer;

procedure SetPriority(Value: Integer);

function GetPolicy: Integer;

procedure SetPolicy(Value: Integer);

procedure SetSuspended(Value: Boolean);

procedure DoTerminate; virtual;

procedure Execute; virtual; abstract;

procedure Synchronize(Method: TThreadMethod);

property ReturnValue: Integer read FReturnValue

property Terminated: Boolean read FTerminated;

constructor Create(CreateSuspended: Boolean);

destructor Destroy; override;

procedure AfterConstruction; override;

function WaitFor: LongWord;

property FatalException: TObject read FFatalException;

property FreeOnTerminate: Boolean read FFreeOnTerminate

property Handle: THandle read FHandle;

property Priority: TThreadPriority read GetPriority

// ** Priority – тип Integer **

property Priority: Integer read GetPriority write SetPriority;

property Policy: Integer read GetPolicy write SetPolicy;

property Suspended: Boolean read FSuspended writeSetSuspended;

property ThreadID: THandle read FThreadID;

// ** ThreadId – тип Cardinal **

property ThreadID: Cardinal read FThreadID;

property OnTerminate: TNotifyEvent read FOnTerminate

Как можно увидеть из объявления, класс TThread — прямой потомок (производный) от класса TObject, следовательно, он не является компонентом. Сравнив блоки кода IFDEF, нетрудно заметить, что класс TThread разработан так, чтобы различия между Delphi и Kylix были минимальными, хотя полностью их избежать все же не удалось. Кроме того, метод TThread.Execute() объявлен абстрактным (abstract). Это озна чает, что класс TThread сам является абстрактным. Таким образом, можно создавать эк земпляры классов, производных от TThread, а экземпляр самого класса TThread соз дать нельзя. Проще всего создать потомок класса TThread с помощью пиктограммы Thread Object в диалоговом окне New Items (рис. 5.1), которое можно открыть, выбрав в меню File пункт New.

Рис. 5.1. Пиктограмма Thread Object

диалогового окна New Items

После выбора элемента Thread Object в диалоговом окне New Items откроется диа логовое окно New Thread Object, в котором будет предложено ввести имя нового объ екта. Например, можно ввести имя TTestThread. Затем Delphi создаст новый модуль, содержащий этот объект. Вот как будет выглядеть его объявление:

procedure Execute; override;

Как видно из примера, для создания функционального потомка класса TThread не

обходимо переопределить единственный метод — Execute(). Предположим теперь,что внутри класса TTestThread требуется выполнить сложные вычисления. В таком случае метод Execute() можно было бы определить следующим образом:

i, Answer: integer;

for i := 1 to 2000000 do

Единственная цель этих вычислений — затратить максимум времени на их выпол

Теперь можно выполнить данный пример потока, вызвав конструктор Create(). В данном случае для этого достаточно щелкнуть на кнопке главной формы, как пока зано в следующем фрагменте программы (во избежание ошибок компилятора не за будьте включить модуль, содержащий объект TTestThread, в раздел uses модуля TForm1):

procedure TForm1.Button1Click(Sender: TObject);

Если запустить приложение и щелкнуть на вышеуказанной кнопке, то можно убе диться, что по прежнему существует возможность работать с формой, т.е. перемещать ее или изменять ее размеры, на фоне выполнения упомянутых вычислений.

Единственный логический параметр, который передается в конструктор Create() класса TThread, называется CreateSuspended. Он определяет, следует ли начинать работу потока с перевода его в приостановленное состояние. Если этот параметр ра- вен False, то метод Execute() создаваемого объекта будет вызван автоматически и без промедления. Если данный параметр равен True, то для действительного запуска потока в определенной точке приложения потребуется вызвать его метод Resume(). Это приведет к выполнению метода Execute() потока и активизирует его. Обычно па- раметр CreateSuspended устанавливается равным True только в том случае, если перед запуском потока требуется установить дополнительные свойства его объекта. Установка свойств объекта после запуска потока может привести к возникновению проблем.

При более внимательном изучении работы конструктора Create() оказывается, что он вызывает функцию библиотеки RTL Delphi BeginThread(), которая, в свою оче- редь, вызывает функцию интерфейса API Win32 CreateThread() для создания ново- го потока. Значение параметра CreateSuspended показывает, нужно ли передавать функции CreateThread() флаг CREATE_SUSPENDED.

Теперь вернемся к методу Execute() класса TTestThread. Обратите внимание: он содержит локальную переменную i. Давайте рассмотрим, что произойдет с пере менной i, если создать два экземпляра класса TTestThread. Может ли значение та кой переменной одного потока перезаписать значением одноименной переменной другого? Имеет ли первый поток преимущество перед вторым? Происходит ли в этом случае аварийное завершение потока? Ответы на все три вопроса одинаковы: нет, нет и нет. Система Win32 поддерживает для каждого работающего в системе потока от дельный стек. Это означает, что при создании нескольких экземпляров класса TTest- Thread каждый из них будет иметь собственную копию переменной i в своем собст венном стеке. Следовательно, в этом отношении все потоки будут действовать неза висимо друг от друга .

Однако необходимо заметить, что понятие “одной и той же” переменной (которая в своем потоке действует независимо от “коллег”) отнюдь не переносится на глобаль ные переменные. Более подробная информация по этой теме приведена в настоящей главе далее.

Поток TThread считается завершенным, когда завершается выполнение его мето да Execute(). В этот момент вызывается стандартная процедура Delphi End- Thread(), которая, в свою очередь, вызывает функцию API Win32 ExitThread(). Данная функция должным образом освобождает стек потока и сам объект потока API. По завершении ее работы поток перестает существовать и все использованные им ре сурсы будут освобождены.

По окончании использования объекта TThread нужно гарантированно уничто жить и соответствующий объект Object Pascal. Только в таком случае можно быть уве ренным в корректном освобождении всей памяти, занимаемой данным объектом. И хотя это происходит автоматически после завершения процесса, возможно придет ся заняться освобождением объекта несколько раньше, чтобы исключить возникно вение утечки памяти в приложении. Простейший способ гарантированно освободить объект TThread состоит в установке его свойства FreeOnTerminate равным значе нию True. Причем это можно сделать в любое время, до завершения выполнения ме тода Execute(). Например, для объекта TTestThread такое свойство устанавливает ся внутри метода Execute():

for i := 1 to 2000000 do

2 Как, впрочем, и экземпляры любых других классов. — Прим. ред. поддерживает также событие OnTerminate, которое происходит при завершении работы потока. Допускается освобождения объекта TThread внутри обработчика этого события.

Событие OnTerminate объекта TThread вызывается в контексте основного потока приложения. Это означает, что внутри обработчика данного события доступ к свойст- вам и методам VCL разрешается выполнять свободно, не прибегая к услугам метода Synchronize(), речь о котором пойдет в следующем разделе.

Следует иметь в виду, что метод Execute() объекта потока самолично несет ответ ственность за проверку состояния свойства Terminated с целью определения необхо димости в досрочном завершении. Хотя это означает еще одно усложнение, о котором следует помнить при работе с потоками, достоинством этой архитектуры класса являет ся полная гарантия того, что никакая “нечистая сила” не выдернет коврик из под ваших ног в самый неподходящий момент. А значит, всегда будет существовать возможность выполнить все необходимые операции очистки по окончании работы потока. Подоб ную проверку состояния свойства Terminated довольно легко добавить в метод Exe- cute() объекта TTestThread — она будет выглядеть следующим образом:

for i := 1 to 2000000 do begin

if Terminated then Break;

В случае аварийной ситуации для завершения выполнения потока можно также ис- пользовать функцию API Win32 TerminateThread(). К этой функции следует обра- щаться только в том случае, если другие варианты отсутствуют — например, когда по- ток попадает в бесконечный цикл и перестает реагировать на сообщения. Эта функция определяется следующим образом:

Свойство THandle объекта TThread содержит дескриптор потока, присвоенный ему функциями API, поэтому к данной функции можно обращаться и с помощью следующе- го синтаксиса:

При использовании этой функции следует помнить о крайне неприятных побочных эффек- тах, которые она способна вызывать. Во-первых, она может вести себя по-разному в опе- рационных системах Windows NT/2000 и Windows 95/98. Под управлением Windows 95/98 функция TerminateThread() освобождает стек, связанный с потоком, а в Windows NT стек не освобождается до тех пор, пока не завершится процесс. Во-вторых, во всех опера-ционных системах Win32 функция TerminateThread(), невзирая ни на что, просто оста-

навливает выполнение в случайном месте и не позволяет

блоку try..finally освободить ресурсы. Это означает, что файлы, открытые потоком, могут остаться незакрытыми, память, выделенная потоком, может не быть освобождена и т.д. Кроме того, динамически компонуемые библиотеки (DLL), загруженные данным процес- сом, не получают соответствующего уведомления при завершении потока с помощью функции TerminateThread(), что может вызвать проблемы при закрытии DLL. Более подробная информация о возможности уведомления DLL о работе потоков приведена в главе 6 “Динамически компонуемые библиотеки”.

Источник: Тейксейра, Стив, Пачеко, Ксавье. Borland Delphi 6. Руководство разработчика. : Пер. с англ. — М. : Издательский дом “Вильямс”, 2002. — 1120 с. : ил. — Парал. тит. англ.

Многопоточность (_beginthread)

Здрасте! Где у меня ошибка? Исправьте, плз..измучался весь..Хочу запустить два потока: в каждом счетчик, однако, почему-то выполняется тока второй поток, а первый вроде как начинается, а потом перехватывается вторым потоком.. Пытался сделать как в мсдн, не получаеца :(

#include
#include
#include

HANDLE hScreenMutex;
HANDLE hRunMutex;

void ThreadFunc(void *arg);

char *str1=»First thread is running.»;
char *str2=»Second thread is running.»;

hScreenMutex = CreateMutex(NULL, FALSE, NULL);
hRunMutex = CreateMutex(NULL, TRUE, NULL);

_beginthread( ThreadFunc, 0, str1);
_beginthread( ThreadFunc, 0, str2);

void ThreadFunc(void *arg)
<
int Count = 100000;
char *str = (char*) arg;
printf(«\n%s\n», str);
do
<
WaitForSingleObject(hScreenMutex, INFINITE);
while( Count)
<

printf(«\r%06d», Count);
Count—;

ReleaseMutex(hScreenMutex);
>while( WaitForSingleObject(hRunMutex, 75l) == WAIT_TIMEOUT);
>

9 ответов

На первый вгляд могу сказать, что

Нафиг тебе здесь мутексы? Хватит и критсекций

void ThreadFunc(void *arg)
<
int Count = 100000;
char *str = (char*) arg;

EnterCriticalSection(. );
printf(«\n%s\n», str);
LeaveCriticalSection(. )

for(; Count; —Count)
<
EnterCriticalSection(. );
printf(«\nthread %s === %06d», str, Count);
LeaveCriticalSection(. )
>

struct thParam
<
HANDLE hMutex;
LPSTR lpStr;
>;

DWORD WINAPI Thread(LPVOID lpParam)
<
HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE);
CONSOLE_SCREEN_BUFFER_INFO csbi;
thParam* pPar = (thParam*)lpParam;

WaitForSingleObject(pPar -> hMutex, INFINITE);
iCount = 100000;
cout hMutex);
return 0;
>
int _tmain(int argc, _TCHAR* argv[])
<
thParam par[2];
char szBuffer1[] = «the first thread»;
char szBuffer2[] = «the second thread»;
HANDLE hMutex = CreateMutex(NULL, FALSE, NULL);
HANDLE hThreads[2];
par[0].hMutex = par[1].hMutex = hMutex;
par[0].lpStr = szBuffer1;
par[1].lpStr = szBuffer2;
hThreads[0] = CreateThread(NULL, 0, Thread, (LPVOID)&par[0], 0, NULL);
hThreads[1] = CreateThread(NULL, 0, Thread, (LPVOID)&par[1], 0, NULL);
WaitForMultipleObjects(2, hThreads, TRUE, INFINITE);
CloseHandle(hThreads[0]);
CloseHandle(hThreads[1]);
CloseHandle(hMutex);
return 0;
>

просто скомпильте так логичней использовать мутекс

Илон Маск рекомендует:  Что такое код getclipbox
Понравилась статья? Поделиться с друзьями:
Кодинг, CSS и SQL
Подпрограмма Routine Обязательный заголовок Required header
_beginthread _beginthread
_beginthreadex _beginthreadex