Thread in windows programming

Windows thread API in the C program

Threads are created in the Windows API using the CreateThread() function, and—just as in Pthreads—a set of attributes like security information, the size of the stack, and a flag for the thread is passed to this function. In the below program, we use the default values for these attributes. (The default values do not initially set the thread to a suspended state and instead make it eligible to be run by the CPU scheduler.) Once the summation thread is created, the parent must wait for it to complete before outputting the value of Sum, as the value is set by the summation thread. In Pthread program, we had the parent thread wait for the summation thread using the pthread join() statement Here, using the WaitForSingleObject() function, we perform the equivalent of this in the Windows API , which causes the creating thread to block until the summation thread has exited. In situations that require waiting for multiple threads to complete, the WaitForMultipleObjects() function is used. This function is passed four parameters −

  • The number of objects to wait for
  • A pointer to the array of objects
  • A flag indicating whether all objects have been signaled.
  • A timeout duration (or INFINITE)

For example, if THandles is an array of thread HANDLE objects of size N, the parent thread can wait for all its child threads to complete with this statement −

WaitForMultipleObjects(N, THandles, TRUE, INFINITE);

Processes, Threads, and Apartments

A process is a collection of virtual memory space, code, data, and system resources. A thread is code that is to be serially executed within a process. A processor executes threads, not processes, so each application has at least one process, and a process always has at least one thread of execution, known as the primary thread. A process can have multiple threads in addition to the primary thread.

Processes communicate with one another through messages, using Microsoft’s Remote Procedure Call (RPC) technology to pass information to one another. There is no difference to the caller between a call coming from a process on a remote machine and a call coming from another process on the same machine.

When a thread begins to execute, it continues until it is killed or until it is interrupted by a thread with higher priority (by a user action or the kernel’s thread scheduler). Each thread can run separate sections of code, or multiple threads can execute the same section of code. Threads executing the same block of code maintain separate stacks. Each thread in a process shares that process’s global variables and resources.

The thread scheduler determines when and how often to execute a thread, according to a combination of the process’s priority class attribute and the thread’s base priority. You set a process’s priority class attribute by calling the SetPriorityClass function , and you set a thread’s base priority with a call to SetThreadPriority.

Multithreaded applications must avoid two threading problems: deadlocks and races. A deadlock occurs when each thread is waiting for the other to do something. The COM call control helps prevent deadlocks in calls between objects. A race condition occurs when one thread finishes before another on which it depends, causing the former to use an uninitialized value because the latter has not yet supplied a valid one. COM supplies some functions specifically designed to help avoid race conditions in out-of-process servers. (See Out-of-Process Server Implementation Helpers.)

The Apartment and the COM Threading Architecture

While COM supports the single-thread-per-process model prevalent before the introduction of multiple threads of execution, you can write code to take advantage of multiple threads, resulting in more efficient applications, by allowing one thread to be executed while another thread waits for some time-consuming operation to complete.

Using multiple threads is not a guarantee of better performance. In fact, because thread factoring is a difficult problem, using multiple threads often causes performance problems. The key is to use multiple threads only if you are very sure of what you are doing.

In general, the simplest way to view the COM threading architecture is to think of all the COM objects in the process as divided into groups called apartments. A COM object lives in exactly one apartment, in the sense that its methods can legally be directly called only by a thread that belongs to that apartment. Any other thread that wants to call the object must go through a proxy.

  • Single-threaded apartments consist of exactly one thread, so all COM objects that live in a single-threaded apartment can receive method calls only from the one thread that belongs to that apartment. All method calls to a COM object in a single-threaded apartment are synchronized with the windows message queue for the single-threaded apartment’s thread. A process with a single thread of execution is simply a special case of this model.
  • Multithreaded apartments consist of one or more threads, so all COM objects that live in an multithreaded apartment can receive method calls directly from any of the threads that belong to the multithreaded apartment. Threads in a multithreaded apartment use a model called free-threading. Calls to COM objects in a multithreaded apartment are synchronized by the objects themselves.
Читайте также:  Как восстановить систему без точек восстановления windows 10

For a description of communication between single-threaded apartments and multithreaded apartments within the same process, see Single-Threaded and Multithreaded Communication.

A process can have zero or more single-threaded apartments and zero or one multithreaded apartment.

In a process, the main apartment is the first to be initialized. In a single-threaded process, this is the only apartment. Call parameters are marshaled between apartments, and COM handles the synchronization through messaging. If you designate multiple threads in a process to be free-threaded, all free threads reside in a single apartment, parameters are passed directly to any thread in the apartment, and you must handle all synchronization. In a process with both free-threading and apartment threading, all free threads reside in a single apartment and all other apartments are single-threaded apartments. A process that does COM work is a collection of apartments with, at most, one multithreaded apartment but any number of single-threaded apartments.

The threading models in COM provide the mechanism for clients and servers that use different threading architectures to work together. Calls among objects with different threading models in different processes are naturally supported. From the perspective of the calling object, all calls to objects outside a process behave identically, no matter how the object being called is threaded. Likewise, from the perspective of the object being called, arriving calls behave identically, regardless of the threading model of the caller.

Interaction between a client and an out-of-process object is straightforward, even when they use different threading models because the client and object are in different processes. COM, interposed between the client and the server, can provide the code for the threading models to interoperate, using standard marshaling and RPC. For example, if a single-threaded object is called simultaneously by multiple free-threaded clients, the calls will be synchronized by COM by placing corresponding window messages in the server’s message queue. The object’s apartment will receive one call each time it retrieves and dispatches messages. However, some care must be taken to ensure that in-process servers interact properly with their clients. (See In-Process Server Threading Issues.)

The most important issue in programming with a multithreaded model is to make your code thread-safe so that messages intended for a particular thread go only to that thread and access to threads is protected.

For more information, see the following topics:

Потоки и асинхронное программирование Threading and async programming

Потоки и асинхронное программирование позволяют приложению выполнять задачи асинхронно параллельными потоками. Threading and async programming enables your app to accomplish work asynchronously in parallel threads.

Ваше приложение может использовать пул потоков для выполнения асинхронных задач в параллельных потоках. Your app can use the thread pool to accomplish work asynchronously in parallel threads. Пул потоков управляет набором потоков и использует очередь для назначения потокам рабочих элементов по мере того, как они становятся доступны. The thread pool manages a set of threads and uses a queue to assign work items to threads as they become available. Пул потоков аналогичен шаблонам асинхронного программирования в среде выполнения Windows, так как его можно использовать для выполнения обширных задач без блокировки пользовательского интерфейса. Однако пул потоков предоставляет более широкие возможности управления, чем шаблоны асинхронного программирования, и его можно использовать для одновременного параллельного выполнения нескольких рабочих элементов. The thread pool is similar to the asynchronous programming patterns available in the Windows Runtime because it can be used to accomplish extended work without blocking the UI, but the thread pool offers more control than the asynchronous programming patterns and you can use it to complete multiple work items in parallel. Вы можете использовать пул потоков: You can use the thread pool to:

для отправки рабочих элементов, управления их приоритетами и отмены рабочих элементов; Submit work items, control their priority, and cancel work items.

для планирования рабочих элементов при помощи таймеров и периодических таймеров; Schedule work items using timers and periodic timers.

Читайте также:  Драйвер тачпада тошиба windows 10

для выделения ресурсов для критически важных рабочих элементов; Set aside resources for critical work items.

для выполнения рабочих элементов в ответ на именованные события и семафоры. Run work items in response to named events and semaphores.

Использование пула потоков экономически более эффективно для управления потоками, так как это сокращает накладные расходы на создание и уничтожение потоков. The thread pool is more efficient at managing threads because it reduces the overhead of creating and destroying threads. Таким образом, пул позволяет оптимизировать потоки для нескольких ядер ЦП и сбалансировать ресурсы потоков между приложениями и во время выполнения фоновых задач. The means it has access to optimize threads across multiple CPU cores, and it can balance thread resources between apps and when background tasks are running. Использовать встроенный пул потоков удобно, так как можно сосредоточиться на написании кода для выполнения задачи, не вдаваясь в механизмы управления потоками. Using the built-in thread pool is convenient because you focus on writing code that accomplishes a task instead of the mechanics of thread management.

Управляемые и неуправляемые потоки в Windows Managed and unmanaged threading in Windows

Управление всеми потоками осуществляется посредством класса Thread , включая потоки, созданные средой CLR или созданные за пределами среды выполнения и входящие в управляемую среду для выполнения кода. Management of all threads is done through the Thread class, including threads created by the common language runtime and those created outside the runtime that enter the managed environment to execute code. Среда выполнения отслеживает в своем процессе все потоки, которые когда-либо выполняли код в управляемой среде. The runtime monitors all the threads in its process that have ever executed code within the managed execution environment. Другие потоки она не отслеживает. It does not track any other threads. Потоки могут входить в управляемую среду выполнения посредством COM-взаимодействия (так как среда выполнения предоставляет управляемые объекты неуправляемой среде в качестве COM-объектов), функции COM DllGetClassObject и вызова неуправляемого кода. Threads can enter the managed execution environment through COM interop (because the runtime exposes managed objects as COM objects to the unmanaged world), the COM DllGetClassObject function, and platform invoke.

Когда неуправляемый поток входит в среду выполнения, например, посредством вызываемой оболочки COM, система проверяет локальное хранилище потока данного потока для поиска внутреннего управляемого объекта Thread . When an unmanaged thread enters the runtime through, for example, a COM callable wrapper, the system checks the thread-local store of that thread to look for an internal managed Thread object. Если он найден, среда выполнения уже оповещена об этом потоке. If one is found, the runtime is already aware of this thread. Если найти объект не удается, среда выполнения создает новый объект Thread и устанавливает его в локальном хранилище потока данного потока. If it cannot find one, however, the runtime builds a new Thread object and installs it in the thread-local store of that thread.

При использовании управляемых потоков Thread.GetHashCode является стабильным средством идентификации управляемого потока. In managed threading, Thread.GetHashCode is the stable managed thread identification. В течение времени существования вашего потока он не будет конфликтовать со значением из любого другого потока независимо от того, из какого домена приложения вы получили это значение. For the lifetime of your thread, it will not collide with the value from any other thread, regardless of the application domain from which you obtain this value.

Сопоставление потоков Win32 с управляемыми потоками Mapping from Win32 threading to managed threading

В следующей таблице элементы потоков Win32 сопоставляются со своими ближайшими аналогами из среды выполнения. The following table maps Win32 threading elements to their approximate runtime equivalent. Обратите внимание, что такое сопоставление не означает идентичную функциональность. Note that this mapping does not represent identical functionality. Например, TerminateThread не выполняет предложения finally , не освобождает ресурсы и не может быть запрещен. For example, TerminateThread does not execute finally clauses or free up resources, and cannot be prevented. Однако Thread.Abort выполняет весь ваш код отката, освобождает все ресурсы и может быть отменен с помощью ResetAbort. However, Thread.Abort executes all your rollback code, reclaims all the resources, and can be denied using ResetAbort. Прежде чем делать предположения о функциональности, тщательно изучите документацию. Be sure to read the documentation closely before making assumptions about functionality.

В Win32 In Win32 В среде CLR In the common language runtime
CreateThread CreateThread Сочетание Thread и ThreadStart Combination of Thread and ThreadStart
TerminateThread TerminateThread Thread.Abort
SuspendThread SuspendThread Thread.Suspend
ResumeThread ResumeThread Thread.Resume
Sleep Sleep Thread.Sleep
WaitForSingleObject в дескрипторе потока WaitForSingleObject on the thread handle Thread.Join
ExitThread ExitThread Эквивалент отсутствует No equivalent
GetCurrentThread GetCurrentThread Thread.CurrentThread
SetThreadPriority SetThreadPriority Thread.Priority
Эквивалент отсутствует No equivalent Thread.Name
Эквивалент отсутствует No equivalent Thread.IsBackground
Близко к CoInitializeEx (OLE32.DLL) Close to CoInitializeEx (OLE32.DLL) Thread.ApartmentState

Управляемые потоки и подразделения COM Managed threads and COM apartments

Управляемый поток может быть отмечен для указания того, что в нем будет размещаться однопотоковое или многопотоковое подразделение. A managed thread can be marked to indicate that it will host a single-threaded or multithreaded apartment. (Дополнительные сведения об архитектуре потоков COM см. в статье Processes, Threads, and Apartments (Процессы, потоки и подразделения)). Методы GetApartmentState, SetApartmentState и TrySetApartmentState класса Thread возвращают и назначают состояние подразделения потока. (For more information on the COM threading architecture, see Processes, Threads, and Apartments.) The GetApartmentState, SetApartmentState, and TrySetApartmentState methods of the Thread class return and assign the apartment state of a thread. Если состояние не задано, GetApartmentState возвращает ApartmentState.Unknown. If the state has not been set, GetApartmentState returns ApartmentState.Unknown.

Свойство можно задать, только когда поток находится в состоянии ThreadState.Unstarted ; его можно задать только один раз для потока. The property can be set only when the thread is in the ThreadState.Unstarted state; it can be set only once for a thread.

Если состояние подразделения не задано до запуска потока, этот поток инициализируется в качестве многопотокового подразделения (MTA). If the apartment state is not set before the thread is started, the thread is initialized as a multithreaded apartment (MTA). Поток метода завершения и все потоки, управляемые ThreadPool , являются многопотоковыми подразделениями. The finalizer thread and all threads controlled by ThreadPool are MTA.

Для кода запуска приложения единственный способ управления состоянием подразделения заключается в применении MTAThreadAttribute или STAThreadAttribute к процедуре точки входа. For application startup code, the only way to control apartment state is to apply the MTAThreadAttribute or the STAThreadAttribute to the entry point procedure.

Управляемые объекты, предоставляемые интерфейсу COM, работают так, как если бы они агрегировали упаковщик в режиме свободного потока. Managed objects that are exposed to COM behave as if they had aggregated the free-threaded marshaler. Другими словами, их можно вызвать из любого подразделения COM в режиме свободного потока. In other words, they can be called from any COM apartment in a free-threaded manner. В таком режиме не работают только управляемые объекты, производные от ServicedComponent или StandardOleMarshalObject. The only managed objects that do not exhibit this free-threaded behavior are those objects that derive from ServicedComponent or StandardOleMarshalObject.

В управляемом коде отсутствует поддержка SynchronizationAttribute , если только вы не используете контексты и контекстно-привязанные управляемые экземпляры. In the managed world, there is no support for the SynchronizationAttribute unless you use contexts and context-bound managed instances. Если вы используете корпоративные службы, ваш объект должен быть производным от ServicedComponent (который сам является производным от ContextBoundObject). If you are using Enterprise Services, then your object must derive from ServicedComponent (which is itself derived from ContextBoundObject).

Когда управляемый код вызывает COM-объекты, он всегда следует правилам COM. When managed code calls out to COM objects, it always follows COM rules. Другими словами, он выполняет вызов через прокси-серверы подразделения COM и оболочки контекста COM+ 1.0, как того требует OLE32. In other words, it calls through COM apartment proxies and COM+ 1.0 context wrappers as dictated by OLE32.

Блокирующие проблемы Blocking issues

Если поток выполняет неуправляемый вызов для операционной системы, которая заблокировала этот поток в неуправляемом коде, среда выполнения не берет на себя управление им для Thread.Interrupt или Thread.Abort. If a thread makes an unmanaged call into the operating system that has blocked the thread in unmanaged code, the runtime will not take control of it for Thread.Interrupt or Thread.Abort. В случае с Thread.Abortсреда выполнения помечает поток как Abort и берет управление, когда он повторно входит в управляемый код. In the case of Thread.Abort, the runtime marks the thread for Abort and takes control of it when it re-enters managed code. Вместо неуправляемой блокировки рекомендуется использовать управляемую блокировку. It is preferable for you to use managed blocking rather than unmanaged blocking. WaitHandle.WaitOne,WaitHandle.WaitAny, WaitHandle.WaitAll, Monitor.Enter, Monitor.TryEnter, Thread.Join, GC.WaitForPendingFinalizers и др. реагируют на Thread.Interrupt и Thread.Abort. WaitHandle.WaitOne,WaitHandle.WaitAny, WaitHandle.WaitAll, Monitor.Enter, Monitor.TryEnter, Thread.Join, GC.WaitForPendingFinalizers, and so on are all responsive to Thread.Interrupt and to Thread.Abort. Кроме того, если ваш поток находится в однопотоковом подразделении, все эти операции управляемой блокировки будут корректно выдавать сообщения в ваше подразделение, пока поток находится в заблокированном состоянии. Also, if your thread is in a single-threaded apartment, all these managed blocking operations will correctly pump messages in your apartment while your thread is blocked.

Потоки и волокна Threads and fibers

Потоковая модель .NET не поддерживает волокна. The .NET threading model does not support fibers. Не следует вызывать неуправляемые функции, которые реализуется с использованием волокон. You should not call into any unmanaged function that is implemented by using fibers. Такие вызовы могут привести к сбою среды выполнения .NET. Such calls may result in a crash of the .NET runtime.

Читайте также:  Драйвер asus p5ql pro для windows 10
Оцените статью