С thread run windows

Windows Threads

Общая схема использования потоков Windows Threads

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

Для создания нескольких дочерних потоков необходимо несколько раз вызвать метод CreateThread

При разработке параллельных приложений на основе явного использования потоков операционной системы Windows важным аспектом является организация согласованного доступа к ресурсам, которые используются несколькими потоками, будь это общие переменные или участки памяти. Такие ресурсы называются общими или разделяемыми. При наличии нескольких потоков необходимо осуществлять синхронизацию их работы – это можно сделать с помощью таких механизмов операционной системы как критические секции, мьютексы, семафоры, события и другие.

Важные положительные моменты технологии Windows threads:

  • Разработка параллельных приложений на основе данной технологии позволяет явно управлять созданием и завершением потоков. Таким образом, обеспечивается контроль за началом и окончанием работы потоков.
  • Явное задание начальных данных и способов их обработки потоками.
  • Возможность достижения более высокого ускорения по сравнению с использованием технологии OpenMP.

Одним из недостатков данной технологии является необходимость реализации согласованного доступа к общим ресурсам и синхронизации выполнения потоков с помощью системных или пользовательских механизмов.

Потоки (threads) в WinAPI

Когда приложение начинает свою работу, для него создаётся процесс (process). Обычно, каждой программе соответствует один процесс.

При создании процесса для него выделяется память — виртуальное адресное пространство (virtual address space). Когда в отладчике мы смотрим на адреса переменных — мы видим адреса из этого пространства.

Потоки (Threads)

Каждый процесс имеет как минимум один поток (thread). До сих пор наши программы состояли из одного процесса и одного потока. В этом уроке мы научимся создавать дополнительные потоки в процессе.

Самый главный вопрос о потоках: для чего нужно несколько потоков? Разные потоки могут одновременно выполняться разными ядрами процессора. Например, в нашей однопоточной программе одна функция просчитывает искусственный интеллект, а другая — физику взаимодействия объектов. В этом случае сначала будет выполнена одна функция, а потом вторая. Если же мы разделим программу на два процесса и запустим программу на двухъядерном процессоре, то искусственный интеллект и физика будут просчитываться одновременно.

Все потоки имеют доступ к адресному пространству процесса. И это может стать серьёзной проблемой. Например, один поток обрабатывает данные и, одновременно, второй пытается вывести эти же данные на экран. Что произойдёт? Успеет ли первый поток обработать все данные, до того как до них доберётся второй поток? Или же второй поток обгонит первый, и часть данных пользователь увидит обработанными, а часть — нет? Эти вопросы мы обсудим в следующих уроках.

С точки зрения C++ поток — это обычная функция имеющая определённый прототип. Для создания потока используется функция CreateThread.

Создание потоков — CreateThread

Функция CreateThread возвращает описатель потока:

!1?HANDLE WINAPI CreateThread( LPSECURITY_ATTRIBUTES lpThreadAttributes, SIZE_T dwStackSize, LPTHREAD_START_ROUTINE lpStartAddress, LPVOID lpParameter, DWORD dwCreationFlags, LPDWORD lpThreadId );?1!

1. lpThreadAttributes — данный аргумент определяет, может ли создаваемый поток быть унаследован дочерним процессом. Мы не будем создавать дочерние процессы, поэтому ставим NULL.

2. dwStackSize — размер стека в байтах. Если передать 0, то будет использоваться значение по-умолчанию (1 мегабайт).

3. lpStartAddress — адрес функции, которая будет выполняться потоком. Т.е. можно сказать, что функция, адрес которой передаётся в этот аргумент, является создаваемым потоком. Данная функция должна соответствовать определённому прототипу — рассмотрим ниже. Имя функции может быть любым — вы сами его выбираете.

4. lpParameter — указатель на переменную, которая будет передана в поток.

5. dwCreationFlags — флаги создания. Здесь можно отложить запуск выполнения потока. Мы будем запускать поток сразу же, передаём 0.

6. lpThreadId — указатель на переменную, куда будет сохранён идентификатор потока. Нам идентификатор не нужен, передаём NULL.

Давайте посмотрим на код вызова CreateThread:

!1?HANDLE thread = CreateThread(NULL,0,thread2,NULL, 0, NULL);?1!

Здесь мы сохраняем описатель потока в переменной thread. Обратите внимание на третий аргумент — адрес функции потока. thread2 — имя функции, которая и будет являться вторым потоком. Вот её код:

Функция потока должна соответствовать следующему прототипу:

!1?DWORD WINAPI ThreadProc(LPVOID lpParameter)?1!

Аргумент, который может принимать данная функция передаётся четвёртым параметров функции CreateThread. Если отбросить все переопределения типов, то данный прототип выглядит так:

!1?unsigned long __stdcall ThreadProc(void* lpParameter)?1!

Напоследок рассмотрим пример создания второго потока:

Создание программы с двумя потоками

Код программы можно скачать в начале урока. Это простая консольная программа. Для работы с потоками необходимо включить файл windows.h. Рассмотрим основной код:

!1?DWORD WINAPI thread2(LPVOID); int main() < cout

View threads in the Visual Studio debugger by using the Threads window (C#, Visual Basic, C++)

In the Threads window, you can examine and work with threads in the application that you’re debugging. For step-by-step guidance on how to use the Threads window, see Walkthrough: Debug by using the Threads window.

Use the Threads window

The Threads window contains a table where each row describes a separate thread in your application. By default, the table lists all the threads in your application, but you can filter the list to show only the threads that interest you. Each column describes a different type of information. You can also hide some columns. If you display all the columns, the following columns appear, from left to right:

Flag: In this unlabeled column, you can mark a thread to which you want to pay special attention. For information about how to flag a thread, see How to: Flag and unflag threads.

Current thread: In this unlabeled column, a yellow arrow indicates the current thread. An arrow outline indicates the current debugger context for a non-current thread.

ID: Displays the identification number for each thread.

Managed ID: Displays the managed identification numbers for managed threads.

Category: Displays the category of threads as either user interface threads, remote procedure call handlers, or worker threads. A special category identifies the main thread of the application.

Name: Identifies each thread by name, if it has one, or as .

Location: Shows where the thread is running. You can expand this location to show the full call stack for the thread.

Priority: An advanced column (hidden by default) that displays the priority or precedence that the system has assigned to each thread.

Affinity Mask: An advanced column (hidden by default) that shows the processor affinity mask for each thread. In a multiprocessor system, the affinity mask determines which processors on which a thread can run.

Suspended Count: An advanced column (hidden by default) that displays the suspended count. This count determines whether a thread can run. For more information about suspended counts, see Freeze and thaw threads.

Process Name: An advanced column (hidden by default) that displays the process to which each thread belongs. The data in this column can be useful when you’re debugging many processes.

Process ID: An advanced column (hidden by default) that displays the process ID to which each thread belongs.

Transport Qualifier: An advanced column (hidden by default) that uniquely identifies the machine to which the debugger is connected.

To display the Threads window in break mode or run mode

  • While Visual Studio is in debug mode, select the Debug menu, point to Windows, and then select Threads.

To display or hide a column

  • In the toolbar at the top of the Threads window, select Columns. Then, select or clear the name of the column that you want to display or hide.

Display flagged threads

You can flag a thread that you want to give special attention by marking it with an icon in the Threads window. For more information, see How to: Flag and Unflag threads. In the Threads window, you can choose to display all the threads or only the flagged threads.

To display only flagged threads

  • Choose Show Flagged Threads Only in the toolbar at the top of the Threads window. (If it’s dimmed, you’ll need to flag some threads first.)

Freeze and thaw threads

When you freeze a thread, the system won’t start execution of the thread even if resources are available.

In native code, you can suspend or resume threads by calling the Windows functions SuspendThread and ResumeThread . Or, call the MFC functions CWinThread::SuspendThread and CWinThread::ResumeThread. If you call SuspendThread or ResumeThread , the suspended count shown in the Threads window will be changed. The suspended count doesn’t change if you freeze or thaw a native thread. A thread can’t execute in native code unless it’s thawed and has a suspended count of zero.

In managed code, the suspended count changes when you freeze or thaw a thread. If you freeze a thread in managed code, its suspended count is 1. When you freeze a thread in native code, its suspended count is 0, unless you used the SuspendThread call.

When you debug a call from native code to managed code, the managed code runs in the same physical thread as the native code that called it. Suspending or freezing the native thread freezes the managed code also.

To freeze or thaw execution of a thread

In the toolbar at the top of the Threads window, select Freeze Threads or Thaw Threads.

This action affects only threads that are selected in the Threads window.

Switch to another thread

A yellow arrow indicates the current thread (and the location of the execution pointer). A green arrow with a curly tail indicates a non-current thread has the current debugger context.

To switch to another thread

Follow either of the following steps:

Double-click any thread.

Right-click a thread and select Switch To Thread.

Group and sort threads

When you group threads, a heading appears in the table for each group. The heading contains a group description, such as Worker Thread or Unflagged Threads, and a tree control. The member threads of each group appear under the group heading. If you want to hide the member threads for a group, use the tree control to collapse the group.

Because grouping takes precedence over sorting, you can group threads by category, for example, and then sort them by ID within each category.

To sort threads

In the toolbar at the top of the Threads window, select the button at the top of any column.

The threads are now sorted by the values in that column.

If you want to reverse the sort order, select the same button again.

Threads that appeared at the top of the list now appear on the bottom.

To group threads

  • In the Threads window toolbar, select the Group by list, then select the criteria that you want to group threads by.

To sort threads within groups

In the toolbar at the top of the Threads window, select the Group by list, then select the criteria that you want to group threads by.

In the Threads window, select the button at the top of any column.

The threads are now sorted by the values in that column.

To expand or collapse all groups

  • In the toolbar at the top of the Threads window, select Expand groups or Collapse groups.

Search for specific threads

You can search for threads that match a specified string in the Threads window. When you search for threads, the window displays all the threads matching the search string in any column. This information includes the thread location that appears at the top of the call stack in the Location column. By default, the full call stack isn’t searched.

To search for specific threads

In the toolbar at the top of the Threads window, go to the Search box and either:

  • Enter a search string and then press Enter.
  • Select the drop-down list next to the Search box and select a search string from a previous search.

(Optional) To include the full call stack in your search, select Search Call Stack.

Display thread call stacks and switch between frames

In a multithreaded program, each thread has its own call stack. The Threads window provides a convenient way to view these stacks.

For a visual representation of the call stack for each thread, use the Parallel Stacks window.

To view the call stack of a thread

In the Location column, select the inverted triangle next to the thread location.

The location expands to show the call stack for the thread.

Creating Threads

The CreateThread function creates a new thread for a process. The creating thread must specify the starting address of the code that the new thread is to execute. Typically, the starting address is the name of a function defined in the program code (for more information, see ThreadProc). This function takes a single parameter and returns a DWORD value. A process can have multiple threads simultaneously executing the same function.

The following is a simple example that demonstrates how to create a new thread that executes the locally defined function, MyThreadFunction .

The calling thread uses the WaitForMultipleObjects function to persist until all worker threads have terminated. The calling thread blocks while it is waiting; to continue processing, a calling thread would use WaitForSingleObject and wait for each worker thread to signal its wait object. Note that if you were to close the handle to a worker thread before it terminated, this does not terminate the worker thread. However, the handle will be unavailable for use in subsequent function calls.

The MyThreadFunction function avoids the use of the C run-time library (CRT), as many of its functions are not thread-safe, particularly if you are not using the multithreaded CRT. If you would like to use the CRT in a ThreadProc function, use the _beginthreadex function instead.

It is risky to pass the address of a local variable if the creating thread exits before the new thread, because the pointer becomes invalid. Instead, either pass a pointer to dynamically allocated memory or make the creating thread wait for the new thread to terminate. Data can also be passed from the creating thread to the new thread using global variables. With global variables, it is usually necessary to synchronize access by multiple threads. For more information about synchronization, see Synchronizing Execution of Multiple Threads.

The creating thread can use the arguments to CreateThread to specify the following:

  • The security attributes for the handle to the new thread. These security attributes include an inheritance flag that determines whether the handle can be inherited by child processes. The security attributes also include a security descriptor, which the system uses to perform access checks on all subsequent uses of the thread’s handle before access is granted.
  • The initial stack size of the new thread. The thread’s stack is allocated automatically in the memory space of the process; the system increases the stack as needed and frees it when the thread terminates. For more information, see Thread Stack Size.
  • A creation flag that enables you to create the thread in a suspended state. When suspended, the thread does not run until the ResumeThread function is called.

You can also create a thread by calling the CreateRemoteThread function. This function is used by debugger processes to create a thread that runs in the address space of the process being debugged.

Читайте также:  Nvidia geforce gtx 750 ti driver linux
Оцените статью