15、Windows API 线程同步

简介: 一、基本概念  常见的线程同步方法(对象)有:      互斥对象(Mutex),事件对象(Event),信号量(Semaphore),临界区(critical section)等。  Synchronization Functions[1]      在同步过程中,两个最重要的概念是同步对象和等待函数。

一、基本概念 

常见的线程同步方法(对象)有: 

    互斥对象(Mutex),事件对象(Event),信号量(Semaphore),临界区(critical section)等。 

Synchronization Functions[1] 

    在同步过程中,两个最重要的概念是同步对象和等待函数。 

    在线程同步过程中,需要先定义一个同步对象,同步对象一般具有两种状态:标志的(置位,signaled)和未标志的(未置位,nonsignaled)。线程根据是否已经完成操作将同步对象设置为标志的或未标志的。

    而等待函数的功能是专门用于等待同步对象状态改变。一个线程调用等待函数后执行会暂停,直到同步对象的状态改变后,等待函数才会返回,线程才会继续执行。等待函数分为“单对象”等待函数和“多对象”等待函数。

What is Signaled State?

One of two possible states for kernel-defined dispatcher objects, which support

synchronization. When the kernel sets such an object to the Signaled state, any threads

waiting on the object are released from their wait and become eligible for execution.

Wait handles have two states, signaled and nonsignaled. A wait handle that is not

owned by any thread is in the signaled state. A wait handle that is owned by a thread is in

the nonsignaled state.[2]

二、同步对象示例[3]

使用事件对象示例

演示使用Event同步线程1
 
   
演示使用Event同步线程
**************************************/

/* 头文件  */
#include
< windows.h >
#include
< stdio.h >
/* 常量定义  */
#define NUMTHREADS 3
#define BUFFER_SIZE 16
#define FOR_TIMES 5
/* 全局变量  */
HANDLE hEvent;
// 用于同步
BYTE lpSharedBuffer[ 16 ] = { 0 }; // 共享内存
/*
函数声明  */
void UseEvents( void );
DWORD WINAPI EventFunction(LPVOID lpParam);

/* ************************************
* int main(void)
* 功能 演示
*
* 参数 未使用
*************************************
*/
int main()
{
UseEvents();
}

/* ************************************
* void UseEvents(void)
* 功能 演示Event的使用方法
*
* 参数 未使用
*************************************
*/
void UseEvents( void )
{
HANDLE hThread;

hEvent
= CreateEvent(
NULL,
// 默认安全属性
TRUE, // 手工重置
FALSE, // 初始为未置位的
NULL // 未命名
);
// 判断是否创建成功
if (hEvent == NULL)
{
printf(
" CreateEvent failed (%d)\n " , GetLastError());
return ;
}
// 创建线程
hThread = CreateThread(NULL, 0 ,
EventFunction,
NULL,
0 , NULL);
if (hThread == NULL)
{
printf(
" CreateThread failed (%d)\n " , GetLastError());
return ;
}
Sleep(
2000 ); // 可以做一些其他处理
// 向共享内存中复制数据
CopyMemory(lpSharedBuffer, " Event " ,lstrlen( " Event " ));
// 设置 Event 使ThreadFunction线程可以开始复制数据
SetEvent(hEvent);
}

/* ************************************
* DWORD WINAPI EventFunction(LPVOID lpParam)
* 功能 线程函数,读共享内存
*
* 参数 未使用
*************************************
*/
DWORD WINAPI EventFunction(LPVOID lpParam)
{
DWORD dwWaitResult;
// 等待,直到事件被置位
dwWaitResult = WaitForSingleObject(
hEvent,
// Event 句柄
INFINITE); // 无限等待
if (dwWaitResult != WAIT_OBJECT_0)
{
printf(
" Wait error: %d\n " , GetLastError());
return 0 ;
}
// 读共享内存
printf(lpSharedBuffer);
// 重置事件
if ( ! ResetEvent(hEvent) )
{
printf(
" SetEvent failed (%d)\n " , GetLastError());
return 0 ;
}
return 1 ;
}
演示使用Event同步线程2
 
   
演示使用Event同步线程
**************************************/

/* 头文件  */
#include
< windows.h >
#include
< stdio.h >
/* 常量定义  */
#define NUMTHREADS 3
#define BUFFER_SIZE 16
#define FOR_TIMES 5
/* 全局变量  */
HANDLE hWriteEvent[NUMTHREADS];
// 写Event 表示写操作是否完成
HANDLE hReadEvents[NUMTHREADS]; // 读Event 表示读操作是否完成
BYTE lpSharedBuffer[ 16 ] = { 0 }; // 共享内存
/*
函数声明  */
void MultiEvents( void );
VOID WriteToBuffer(VOID);
DWORD WINAPI ThreadFunction(LPVOID lpParam);

/* ************************************
* int main(void)
* 功能 演示
*
* 参数 未使用
*************************************
*/
int main()
{
MultiEvents();
}

/* ************************************
* void UseEvents(void)
* 功能 演示Event的使用方法
*
* 参数 未使用
*************************************
*/
void MultiEvents( void )
{
HANDLE hThread;
DWORD i;
// 创建多个线程,读共享内存,主线程写共享内存。
// 每个线程都有对应的读写同步事件
for (i = 0 ; i < NUMTHREADS; i ++ )
{
// 每个线程都有一个Event表示写入操作完成
hWriteEvent[i] = CreateEvent(
NULL,
// 默认安全属性
FALSE, // 自动重置
FALSE, // 初始为未置位的
NULL // 未命名
);
// 判断是否创建成功
if (hWriteEvent[i] == NULL)
{
printf(
" CreateEvent failed (%d)\n " , GetLastError());
return ;
}
// 每个读线程有一个Event表示读操作已经完成
hReadEvents[i] = CreateEvent(
NULL,
// 默认安全属性
FALSE, // 自动重置
FALSE, // 初始化为未置位的
NULL); // 未命名
if (hReadEvents[i] == NULL)
{
printf(
" CreateEvent failed (%d)\n " , GetLastError());
return ;
}
// 创建线程
hThread = CreateThread(NULL, 0 ,
ThreadFunction,
(LPVOID)i,
// Event对象句柄作为
0 , NULL);
if (hThread == NULL)
{
printf(
" CreateThread failed (%d)\n " , GetLastError());
return ;
}
}
WriteToBuffer();
}

/* ************************************
* VOID WriteToBuffer(INT iContent)
* 功能 由主线程调用,向共享内存中写入数据
* 等待所有读线程读完后函数返回
*
* 参数 未使用
*************************************
*/
VOID WriteToBuffer(VOID)
{
DWORD dwWaitResult, j,i;
// 完成 FOR_TIMES 次读写
for (j = 0 ; j < FOR_TIMES; j ++ )
{
Sleep(rand()
% 100 ); // 写入需要的时间随机
// 写入共享内存
wsprintf(lpSharedBuffer, " shared %d " ,j);
// 将线程对应的写Event置为“标志的”,表示写操作完成,
// 其他线程可以开始读
for (i = 0 ; i < NUMTHREADS; i ++ )
{
if ( ! SetEvent(hWriteEvent[i]) )
{
printf(
" SetEvent failed (%d)\n " , GetLastError());
return ;
}
}
// 等待所有的线程读完,开始下次写入
dwWaitResult = WaitForMultipleObjects(
NUMTHREADS,
// Event句柄的个数
hReadEvents, // Event句柄数组
TRUE, // 等到所有的Event都被标志
INFINITE); // 无限等待
// 判断等待结果
if (dwWaitResult != WAIT_OBJECT_0)
{
printf(
" Wait error: %d\n " , GetLastError());
ExitProcess(
0 );
}
}
}

/* ************************************
* DWORD WINAPI ThreadFunction(LPVOID lpParam)
* 功能 线程函数,读共享内存
*
* 参数 LPVOID lpParamt 实际为指向Event句柄的指针
*************************************
*/
DWORD WINAPI ThreadFunction(LPVOID lpParam)
{
DWORD dwWaitResult;
BYTE lpRead[
16 ];
DWORD j
= 0 ;
DWORD dwThreadIndex
= (DWORD)lpParam;
// 完成 FOR_TIMES 次读写
for (; j < FOR_TIMES; j ++ )
{
// 等待写事件置位,表示数据已经写入
dwWaitResult = WaitForSingleObject(
hWriteEvent[dwThreadIndex],
// Event 句柄
INFINITE); // 无限等待
switch (dwWaitResult)
{
case WAIT_OBJECT_0:
Sleep(rand()
% 10 ); // 模拟数据处理所需的时间随机
CopyMemory(lpRead,lpSharedBuffer, 16 );
break ;
// 发生错误
default :
printf(
" Wait error: %d\n " , GetLastError());
ExitThread(
0 );
}
// 将读Event置位,表示读操作完成
if ( ! SetEvent(hReadEvents[dwThreadIndex]) )
{
printf(
" SetEvent failed (%d)\n " , GetLastError());
return 0 ;
}
// 打印读到的内容
printf( " 线程 %u\t第 %d 次读,内容:%s\n " ,
dwThreadIndex,j,(LPSTR)lpRead);
}
return 1 ;
}
参考

[1] http://msdn.microsoft.com/en-us/library/ms686360%28VS.85%29.aspx

[2] http://msdn.microsoft.com/en-us/library/fxy8dte8%28VS.71%29.aspx

[3] 精通Windows API 函数、接口、编程实例

[4] http://www.cnblogs.com/mydomain/archive/2010/11/07/1870994.html

目录
相关文章
|
5月前
|
监控 编译器 API
[笔记]Windows核心编程《二十二》注入DLL和拦截API(一)
[笔记]Windows核心编程《二十二》注入DLL和拦截API
120 0
|
5月前
|
安全 Java API
9.2 运用API实现线程同步
Windows 线程同步是指多个线程一同访问共享资源时,为了避免资源的并发访问导致数据的不一致或程序崩溃等问题,需要对线程的访问进行协同和控制,以保证程序的正确性和稳定性。Windows提供了多种线程同步机制,以适应不同的并发编程场景。以上同步机制各有优缺点和适用场景,开发者应根据具体应用场景进行选择和使用。在线程同步的实现过程中,需要注意竞争条件和死锁的处理,以确保程序中的线程能协同工作,共享资源能够正确访问和修改。线程同步是并发编程中的重要基础,对于开发高效、稳定的并发应用至关重要。
|
2月前
|
API Python Windows
python3应用windows api对后台程序窗口及桌面截图并保存的方法
python3应用windows api对后台程序窗口及桌面截图并保存的方法
58 1
|
5月前
|
存储 缓存 API
[总结]Windows Crypto API 自动更新根证书问题原因及解决方案
[总结]Windows Crypto API 自动更新根证书问题原因及解决方案
|
5月前
|
API Windows
[笔记]Windows核心编程《番外篇》常用的NT API及使用示例
[笔记]Windows核心编程《番外篇》常用的NT API及使用示例
|
5月前
|
安全 API Windows
[笔记]Windows核心编程《二十二》注入DLL和拦截API(三)
[笔记]Windows核心编程《二十二》注入DLL和拦截API(三)
106 0
|
5月前
|
消息中间件 编解码 安全
[笔记]Windows核心编程《二十二》注入DLL和拦截API(二)
[笔记]Windows核心编程《二十二》注入DLL和拦截API(二)
|
5月前
|
存储 API 调度
[笔记]Windows核心编程《八》用内核对象进行线程同步
[笔记]Windows核心编程《八》用内核对象进行线程同步
|
5月前
|
缓存 编译器 调度
[笔记]Windows核心编程《七》用户模式下的线程同步
[笔记]Windows核心编程《七》用户模式下的线程同步
|
5月前
|
API C++ Windows
Windows API Hooking 学习
Windows API Hooking 学习

相关产品

  • 云迁移中心