当前位置:网站首页>Summary of thread and thread synchronization under window
Summary of thread and thread synchronization under window
2022-07-05 11:11:00 【Chenziqing: see】
Catalog
Thread creation function CreateThread And _beginthreadex
Wait function WaitForSingleObject and WaitForMultipleObjects
Mutually exclusive objects use
CreateMutex The function prototype
Key code snippets -( A critical region )
Comparison of four ways of thread synchronization
One Thread creation and use
Thread creation function CreateThread And _beginthreadex
CreateThread It's a kind of Microsoft in Windows API The function to create a new thread is provided in , The function is in The main thread Create a new thread based on . Threads After terminating the operation , The thread object is still in the system , Must pass CloseHandle Function to close the Thread object . The function prototype is as follows
HANDLE CreateThread(
LPSECURITY_ATTRIBUTES lpThreadAttributes,//SD
SIZE_T dwStackSize,//initialstacksize
LPTHREAD_START_ROUTINE lpStartAddress,//threadfunction
LPVOID lpParameter,//threadargument
DWORD dwCreationFlags,//creationoption
LPDWORD lpThreadId//threadidentifier
)
- The first parameter lpThreadAttributes Represents the security properties of thread kernel objects , General introduction NULL Indicates using the default settings .
- The second parameter dwStackSize Indicates the size of thread stack space . Pass in 0 Indicates using the default size (1MB).
- The third parameter lpStartAddress Represents the address of the thread function executed by the new thread , Multiple threads can use the same function address .
- Fourth parameter lpParameter Is the parameter passed to the thread function .
- Fifth parameter dwCreationFlags Specify additional flags to control thread creation , by 0 Indicates that the thread can be scheduled immediately after it is created , If CREATE_SUSPENDED Indicates that the thread is suspended after creation , So it can't schedule , Until the call ResumeThread().
- Sixth parameter lpThreadId Will return the ID Number , Pass in NULL Indicates that the thread does not need to be returned ID Number
Return value : // Successfully returned new thread handle , Failure to return 0
_beginthreadex It's right CreateThread Function optimization , The use method is basically the same . The function prototype is as follows
unsigned long _beginthreadex(
void *security, // Security attribute , by NULL Indicates the default security
unsigned stack_size, // The stack size of the thread , The general default is 0
unsigned(_stdcall *start_address)(void *), // Thread functions
void *argilist, // Parameters of thread function
unsigned initflag, // The initial state of the new thread ,0 Means to execute immediately ,//CREATE_SUSPENDED Indicates pending after creation
unsigned *threaddr // Used to receive threads ID
);
Return value : // Successfully returned new thread handle , Failure to return 0
Wait function WaitForSingleObject and WaitForMultipleObjects
The functionality : Wait function – Put the thread in wait , Until the specified kernel object is triggered . The function prototype is as follows
DWORDWINAPIWaitForSingleObject(
HANDLEhHandle,
DWORDdwMilliseconds
);
Function description :
The first parameter is the kernel object to wait for .
The second parameter is the longest waiting time , In Milliseconds , Such as incoming 5000 It means 5 second , Pass in 0 Go back now , Pass in INFINITE It means infinite waiting .
Because the handle of the thread is not triggered when the thread is running , Thread ends running , Handle is in trigger state . So it can be used WaitForSingleObject() To wait for a thread to finish running .
Function return value :
The object is triggered within the specified time , The function returns WAIT_OBJECT_0. The object that has exceeded the maximum waiting time has not been triggered to return WAIT_TIMEOUT. Errors in the passed in parameters will be returned WAIT_FAILED
WaitForMultipleObjects(
_In_DWORD nCount, // The number of handles of the group of handles to be monitored
_In_reads_(nCount) CONSTHANDLE* lpHandles, // The group of handles to monitor
_In_BOOL bWaitAll, // TRUE Wait for all kernel objects to signal , FALSE Any kernel object sends a signal
_In_DWORD dwMilliseconds // Waiting time
);
Routine code
#include <stdio.h>
#include <windows.h>
#include <process.h>
unsigned int WINAPI ThreadFun(LPVOID p)
{
int cnt = *((int*)p);
for (int i = 0; i < cnt; i++)
{
Sleep(1000);
puts("running thread");
}
return 0;
}
int main()
{
printf("main begin\n");
int iParam = 5;
unsigned int dwThreadID;
DWORD wr;
HANDLE hThread = (HANDLE)_beginthreadex(NULL, 0, ThreadFun,
(void*)&iParam, 0, &dwThreadID);
if (hThread == NULL)
{
puts("_beginthreadex() error");
return -1;
}
//
printf("WaitForSingleObject begin\n");
if ((wr = WaitForSingleObject(hThread, INFINITE)) == WAIT_FAILED)
{
puts("thread wait error");
return -1;
}
printf("WaitForSingleObject end\n");
printf("main end\n");
system("pause");
return 0;
}
Two Thread synchronization
Mutexes
Mutually exclusive objects use
(mutex) Belongs to kernel object , It ensures that threads have mutually exclusive access to individual resources .
The mutex object contains a The amount used , One thread ID And a counter . The thread ID It is used to identify which thread in the system currently owns mutually exclusive objects , The counter is used to indicate the number of times that this thread has mutually exclusive objects .
Create mutex : Call function CreateMutex. Successful call , This function returns the handle of the created mutex .
Request ownership of mutually exclusive objects : Call function WaitForSingleObject function . Threads must actively request ownership of shared objects to obtain ownership .
Release ownership of the specified mutex : call ReleaseMutex function . After the thread accesses the shared resource , Threads should actively release the ownership of mutually exclusive objects , Put the object in the notified state .
CreateMutex The function prototype
HANDLE WINAPI CreateMutexW(
_In_opt_LPSECURITY_ATTRIBUTES lpMutexAttributes, // Point to security attribute
_In_BOOL bInitialOwner, // Initializes the owner of the mutex TRUE Have mutex immediately ,false Represents the created mutex Does not belong to any thread ; So in the excited state , That is, there is a signal state
_In_opt_LPCWSTR lpName // Pointer to mutex name L“Bingo”
);
Routine code
#include <stdio.h>
#include <windows.h>
#include <process.h>
#define NUM_THREAD 50
unsigned WINAPI threadInc(void * arg);
unsigned WINAPI threadDes(void * arg);
long long num=0;
HANDLE hMutex;
int main(int argc, char *argv[])
{
HANDLE tHandles[NUM_THREAD];
int i;
hMutex=CreateMutex(NULL, FALSE, NULL);
for(i=0; i<NUM_THREAD; i++)
{
if(i%2)
tHandles[i]=(HANDLE)_beginthreadex(NULL, 0, threadInc, NULL, 0, NULL);
else
tHandles[i]=(HANDLE)_beginthreadex(NULL, 0, threadDes, NULL, 0, NULL);
}
WaitForMultipleObjects(NUM_THREAD, tHandles, TRUE, INFINITE);
CloseHandle(hMutex);
printf("result: %lld \n", num);
return 0;
}
unsigned WINAPI threadInc(void * arg)
{
int i;
WaitForSingleObject(hMutex, INFINITE);
for(i=0; i<500000; i++)
num+=1;
ReleaseMutex(hMutex);
return 0;
}
unsigned WINAPI threadDes(void * arg)
{
int i;
WaitForSingleObject(hMutex, INFINITE);
for(i=0; i<500000; i++)
num-=1;
ReleaseMutex(hMutex);
return 0;
}
Event object
Use of event objects
Event objects also belong to kernel objects , It contains the following three members :
● Use count ;
● Boolean value used to indicate whether the event is an automatic reset event or a manual reset event ;
● Boolean value used to indicate whether the event is in the notified state or not .
There are two types of event objects : Manually reset event object and Automatically reset the event object . The difference between these two event objects is that when the manually reset event object is notified , All threads waiting for this event object become schedulable ; When an automatically reset event object is notified , Only one of the threads waiting for the event object becomes a schedulable thread .
1. Create event object
call CreateEvent Function to create or open a named or anonymous event object .
2. Set event object status
call SetEvent Function to set the specified event object to signaled state .
3. Reset event object state
call ResetEvent Function to set the specified event object to the no signal state .
4. Request event object
The thread calls WaitForSingleObject Function request event object .
The function prototype
HANDLE CreateEvent(
LPSECURITY_ATTRIBUTES lpEventAttributes, // Security attribute
BOOL bManualReset, // Reset mode TRUE Must use ResetEvent Manual recovery FALSE Automatically restore to no signal stateBOOL bInitialState, // The initial state TRUE The initial state is signalized FALSE No signal state
LPCTSTR lpName // Object name NULL Nameless event object
);
Routine code
/*
Enter a global string : ABCD AAADDD
Determine how many letters there are through multithreading A, It must be realized by thread synchronization ;
Event object :
*/
#include <stdio.h>
#include <windows.h>
#include <process.h>
#define STR_LEN 100
unsigned WINAPI NumberOfA(void* arg);
unsigned WINAPI NumberOfOthers(void* arg);
static char str[STR_LEN];
static HANDLE hEvent;
int main(int argc, char* argv[])
{
HANDLE hThread1, hThread2;
fputs("Input string: ", stdout);
fgets(str, STR_LEN, stdin);
//NUll Default security symbol Manual FALSE The initial state is no signal state
hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
hThread1 = (HANDLE)_beginthreadex(NULL, 0, NumberOfA, NULL, 0, NULL);
hThread2 = (HANDLE)_beginthreadex(NULL, 0, NumberOfOthers, NULL, 0, NULL);
WaitForSingleObject(hThread1, INFINITE);
WaitForSingleObject(hThread2, INFINITE);
// until 2 After the threads are executed , Then set the event to no signal state
ResetEvent(hEvent);
CloseHandle(hEvent);
system("pause");
return 0;
}
unsigned WINAPI NumberOfA(void* arg)
{
int i, cnt = 0;
// No more execution fputs("Input string: ", stdout);
//fgets(str, STR_LEN, stdin);SetEvent(hEvent); Before , Stuck in
//WaitForSingleObject
WaitForSingleObject(hEvent, INFINITE);
for (i = 0; str[i] != 0; i++)
{
if (str[i] == 'A')
cnt++;
}
printf("Num of A: %d \n", cnt);
return 0;
}
unsigned WINAPI NumberOfOthers(void* arg)
{
int i, cnt = 0;
// No more execution fputs("Input string: ", stdout);
//fgets(str, STR_LEN, stdin);SetEvent(hEvent); Before , Stuck in
//WaitForSingleObject
// WaitForSingleObject(hEvent, INFINITE);
for (i = 0; str[i] != 0; i++)
{
if (str[i] != 'A')
cnt++;
}
printf("Num of others: %d \n", cnt - 1);
// Set the event object to signaled state
SetEvent(hEvent);
return 0;
}
Key code snippets -( A critical region )
Use of key code segments
Key code snippets , Also known as A critical region , Work in user mode . It refers to a Small code snippet , Before the code can execute , It has to Exclusive access to certain resources . The part of code that accesses the same resource in multiple threads is usually regarded as a key code segment .
Initialize key code snippets - call InitializeCriticalSection Function initializes a key code segment .
InitializeCriticalSection(
_Out_LPCRITICAL_SECTION lpCriticalSection
);
This function has only one point CRITICAL_SECTION Pointer to structure . Calling InitializeCriticalSection Function before , First, we need to construct a CRITICAL_SECTION Objects of structure type , Then pass the address of the object to InitializeCriticalSection function .
Enter key code snippets - call EnterCriticalSection function , To obtain ownership of the specified critical area object , This function waits for ownership of the specified critical zone object , If this ownership is given to the calling thread , Then the function returns ; Otherwise, the function will wait , This causes the thread to wait .
Exit critical code snippets - After the thread uses the resources protected by the critical area , Need to call LeaveCriticalSection function , Release the ownership of the specified critical area object . after , Other threads that want to get the ownership of the critical area object can get the ownership , To enter the key code segment , Access protected resources .
Delete critical area - When the critical zone is no longer needed , You can call DeleteCriticalSection Function to release the object , This function will release all resources of a critical zone object that is not owned by any thread .
Routine code
#include <stdio.h>
#include <windows.h>
#include <process.h>
int iTickets = 5000;
CRITICAL_SECTION g_cs;
// A window B window
DWORD WINAPI SellTicketA(void* lpParam)
{
while (1)
{
EnterCriticalSection(&g_cs);// Enter the critical area
if (iTickets > 0)
{
Sleep(1);
iTickets--;
printf("A remain %d\n", iTickets);
LeaveCriticalSection(&g_cs);// Get out of the critical area
}
else
{
LeaveCriticalSection(&g_cs);// Get out of the critical area
break;
}
}
return 0;
}
DWORD WINAPI SellTicketB(void* lpParam)
{
while (1)
{
EnterCriticalSection(&g_cs);// Enter the critical area
if (iTickets > 0)
{
Sleep(1);
iTickets--;
printf("B remain %d\n", iTickets);
LeaveCriticalSection(&g_cs);// Get out of the critical area
}
else
{
LeaveCriticalSection(&g_cs);// Get out of the critical area
break;
}
}
return 0;
}
int main()
{
HANDLE hThreadA, hThreadB;
hThreadA = CreateThread(NULL, 0, SellTicketA, NULL, 0, NULL); //2
hThreadB = CreateThread(NULL, 0, SellTicketB, NULL, 0, NULL); //2
CloseHandle(hThreadA); //1
CloseHandle(hThreadB); //1
InitializeCriticalSection(&g_cs); // Initialize key code snippets
Sleep(40000);
DeleteCriticalSection(&g_cs);// Delete critical area
system("pause");
return 0;
}
Semaphore Semaphore
Semaphore details
- The state of the kernel object :
Trigger state ( Signal status ), Indicates that there are available resources .
Not triggered ( No signal state ), Indicates that no resources are available
- The composition of semaphores
① Counter : The number of times the kernel object was used
② The maximum number of resources : Identify the maximum number of resources that the semaphore can control ( Signed 32 position )
③ The current number of resources : Identify the number of currently available resources ( Signed 32 position ). It indicates that the Number of current open resources ( Be careful Not the number of remaining resources ), Only open resources can be applied by threads . But these open resources are not necessarily occupied by threads . such as , Currently open 5 A resource , And only 3 Threads apply , Then there is 2 Resources can be applied , But if the total is 7 Threads need semaphores , Obviously open resources 5 One is not enough . At this time, it can be reopened 2 individual , Until the maximum number of resources is reached .
The rules of semaphore are as follows :
(1) If the current resource count is greater than 0, Then the semaphore is in the trigger state ( Signal status ), Indicates that there are available resources .
(2) If the current resource count equals 0, Then the semaphore belongs to the non triggered state ( No signal state ), Indicates that no resources are available .
(3) The system will never make the current resource count negative
(4) The current resource count will never be greater than the maximum resource count
The difference between semaphores and mutexes is , It allows multiple threads to access the same resource at the same time , But it needs to be limited to The maximum number of threads accessing this resource at the same time . The synchronization of semaphore object to thread is different from the previous methods , Signals allow multiple threads to use shared resources at the same time .
The function prototype
Create semaphores CreateSemaphoreW
HANDLE WINAPI CreateSemaphoreW(
_In_opt_LPSECURITY_ATTRIBUTES lpSemaphoreAttributes, // Null Security attribute
_In_LONG lInitialCount, // On initialization , How many resources are available . 0: Non triggered state // state ( No signal state ), Indicates that no resources are available
_In_LONG lMaximumCount, // The maximum number of resources that can be processed
_In_opt_LPCWSTR lpName //NULL The name of the semaphore
);
Increase the semaphore ReleaseSemaphore
WINAPI ReleaseSemaphore(
_In_HANDLE hSemaphore, // Handle to semaphore
_In_LONG lReleaseCount, // take lReleaseCount Value is added to the current resource count of the semaphore
_Out_opt_LPLONG lpPreviousCount // The original value of the current resource count
);
Routine code
#include <stdio.h>
#include <windows.h>
#include <process.h>
unsigned WINAPI Read(void* arg);
unsigned WINAPI Accu(void* arg);
static HANDLE semOne;
static HANDLE semTwo;
static int num;
int main(int argc, char* argv[])
{
HANDLE hThread1, hThread2;
semOne = CreateSemaphore(NULL, 0, 1, NULL);
//semOne No resources available It can only mean 0 perhaps 1 The binary semaphore of No signal
semTwo = CreateSemaphore(NULL, 1, 1, NULL);
//semTwo There are resources available , Signal status There is a signal
hThread1 = (HANDLE)_beginthreadex(NULL, 0, Read, NULL, 0, NULL);
hThread2 = (HANDLE)_beginthreadex(NULL, 0, Accu, NULL, 0, NULL);
WaitForSingleObject(hThread1, INFINITE);
WaitForSingleObject(hThread2, INFINITE);
CloseHandle(semOne);
CloseHandle(semTwo);
system("pause");
return 0;
}
unsigned WINAPI Read(void* arg)
{
int i;
for (i = 0; i < 5; i++)
{
fputs("Input num: ", stdout); // 1 5 11
printf("begin read\n"); // 3 6 12
// Waiting for kernel objects semTwo The signal of , If there's a signal , Carry on ; If there's no signal , wait for
WaitForSingleObject(semTwo, INFINITE);
printf("beginning read\n"); //4 10 16
scanf("%d", &num);
ReleaseSemaphore(semOne, 1, NULL);
}
return 0;
}
unsigned WINAPI Accu(void* arg)
{
int sum = 0, i;
for (i = 0; i < 5; i++)
{
printf("begin Accu\n"); //2 9 15
// Waiting for kernel objects semOne The signal of , If there's a signal , Carry on ; If there's no signal , wait for
WaitForSingleObject(semOne, INFINITE);
printf("beginning Accu\n"); //7 13
sum += num;
printf("sum = %d \n", sum); // 8 14
ReleaseSemaphore(semTwo, 1, NULL);
}
printf("Result: %d \n", sum);
return 0;
}
Comparison of four ways of thread synchronization
Compare | The mutex Mutex | Event object Event | Semaphore object Semaphore | Key code snippets Criticalsection |
Whether it is a kernel object | yes | yes | yes | no |
Speed | slower | slower | slow | fast |
Thread synchronization in multiple processes | Support | Support | Support | I won't support it |
There's a deadlock | no | no | no | yes |
form | One thread ID; Used to identify which thread owns the mutex ; A counter : Used to know the number of times this thread is used for mutually exclusive objects | A usage count ; A Boolean value : It is used to identify whether the event is reset automatically or manually ; A Boolean value : Identify whether the event is in a signaled state or a non signaled state | A usage count ; The maximum number of resources ; Identify the number of resources currently available | A small code snippet ; Before the code can execute , Must occupy access to certain resources |
Correlation function | CreateMutex WaitForSingleObjects // Protected content ReleaseMutex | CreateEvent ResetEvent WaitforSingleobject // Protection content SetEvent | CreateSemaphore WaitForsingleobject // Protected content ReleaseSemaPhore | InitialCriticalSection EnterCritionSection // Protected content LeaveCritialSection DeleteCritialSection |
matters needing attention | Who owns mutually exclusive objects , Who released ; If you request the same mutex in the same thread multiple times , Need to call more than once releaseMutex | To achieve synchronization between threads , Manual reset should not be used , The second parameter should be set false; Set to automatic reset | It allows multiple threads to access the same resource at the same time ; However, you need to limit the maximum number of threads accessing this resource ; | Prevent deadlock : When using multiple key code segment variables |
analogy | A key | The key ( Automatically / artificial ) | Parking lot and security | Telephone booth |
thread deadlock
Deadlock is a deadlock caused by multiple threads competing for resources ( Waiting for each other ), If there is no external force , None of these processes will move forward .
When using key code snippets , It is easy to enter a deadlock state , Because the timeout value cannot be set while waiting to enter the critical code segment
The code for
#include <stdio.h>
#include <windows.h>
#include <process.h>
int iTickets = 5000;
CRITICAL_SECTION g_csA;
CRITICAL_SECTION g_csB;
// A window B window
DWORD WINAPI SellTicketA(void* lpParam)
{
while (1)
{
EnterCriticalSection(&g_csA);// Enter the critical area A
Sleep(1);
EnterCriticalSection(&g_csB);// Enter the critical area B
if (iTickets > 0)
{
Sleep(1);
iTickets--;
printf("A remain %d\n", iTickets);
LeaveCriticalSection(&g_csB);// Get out of the critical area B
LeaveCriticalSection(&g_csA);// Get out of the critical area A
}
else
{
LeaveCriticalSection(&g_csB);// Get out of the critical area B
LeaveCriticalSection(&g_csA);// Get out of the critical area A
break;
}
}
return 0;
}
DWORD WINAPI SellTicketB(void* lpParam)
{
while (1)
{
EnterCriticalSection(&g_csB);// Enter the critical area B
Sleep(1);
EnterCriticalSection(&g_csA);// Enter the critical area A
if (iTickets > 0)
{
Sleep(1);
iTickets--;
printf("B remain %d\n", iTickets);
LeaveCriticalSection(&g_csA);// Get out of the critical area A
LeaveCriticalSection(&g_csB);// Get out of the critical area B
}
else
{
LeaveCriticalSection(&g_csA);// Get out of the critical area A
LeaveCriticalSection(&g_csB);// Get out of the critical area B
break;
}
}
return 0;
}
int main()
{
HANDLE hThreadA, hThreadB;
hThreadA = CreateThread(NULL, 0, SellTicketA, NULL, 0, NULL); //2
hThreadB = CreateThread(NULL, 0, SellTicketB, NULL, 0, NULL); //2
CloseHandle(hThreadA); //1
CloseHandle(hThreadB); //1
InitializeCriticalSection(&g_csA); // Initialize key code snippets A
InitializeCriticalSection(&g_csB); // Initialize key code snippets B
Sleep(40000);
DeleteCriticalSection(&g_csA);// Delete critical area
DeleteCriticalSection(&g_csB);// Delete critical area
system("pause");
return 0;
}
边栏推荐
- Share Net lightweight ORM
- 基于昇腾AI丨以萨技术推出视频图像全目标结构化解决方案,达到业界领先水平
- 2021年山东省赛题库题目抓包
- 关于 “原型” 的那些事你真的理解了吗?【上篇】
- Process control
- 2022 chemical automation control instrument examination questions and online simulation examination
- Some understandings of heterogeneous graphs in DGL and the usage of heterogeneous graph convolution heterographconv
- When using gbase 8C database, an error is reported: 80000502, cluster:%s is busy. What's going on?
- 修复动漫1K变8K
- 基础篇——REST风格开发
猜你喜欢
About the use of Vray 5.2 (self research notes) (II)
DDR4的特性与电气参数
Honing · fusion | know that the official website of Chuangyu mobile terminal is newly launched, and start the journey of digital security!
About the use of Vray 5.2 (self research notes)
9、 Disk management
磨砺·聚变|知道创宇移动端官网焕新上线,开启数字安全之旅!
7.2每日学习4
Web3 Foundation grant program empowers developers to review four successful projects
matlab cov函数详解
2022 t elevator repair operation certificate examination questions and answers
随机推荐
Taro advanced
Talk about the understanding of fault tolerance mechanism and state consistency in Flink framework
2022 Pengcheng cup Web
How can gbase 8C database view the login information of the login user, such as the date, time and IP of the last login authentication?
【广告系统】增量训练 & 特征准入/特征淘汰
NAS and San
Deepfake tutorial
vite//
Variables///
Applet framework taro
Data type
A usage example that can be compatible with various database transactions
[JS learning notes 54] BFC mode
Wechat nucleic acid detection appointment applet system graduation design completion (7) Interim inspection report
使用bat命令一键启动常用浏览器
LSTM applied to MNIST dataset classification (compared with CNN)
R3Live系列学习(四)R2Live源码阅读(2)
Web3基金会「Grant计划」赋能开发者,盘点四大成功项目
iframe
2022 t elevator repair operation certificate examination questions and answers