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

目录
相关文章
|
10月前
|
调度 Windows
|
9天前
|
人工智能 测试技术 API
Windows用户必备:Postman v11详细安装指南与API测试入门教程(附官网下载
Postman是全球领先的API开发与测试工具,支持REST、SOAP、GraphQL等协议调试。2025年最新版v11新增AI智能生成测试用例、多环境变量同步等功能,适用于前后端分离开发、自动化测试、接口文档自动生成及团队协作共享API资源。本文详细介绍Postman的软件定位、核心功能、安装步骤、首次配置、基础使用及常见问题解答,帮助用户快速上手并高效利用该工具进行API开发与测试。
|
5月前
|
开发框架 .NET API
Windows Forms应用程序中集成一个ASP.NET API服务
Windows Forms应用程序中集成一个ASP.NET API服务
132 9
|
6月前
|
网络协议 API Windows
MASM32编程调用 API函数RtlIpv6AddressToString,windows 10 容易,Windows 7 折腾
MASM32编程调用 API函数RtlIpv6AddressToString,windows 10 容易,Windows 7 折腾
|
7月前
|
安全 Java API
|
7月前
|
Java Windows
【Azure Developer】Windows中通过pslist命令查看到Java进程和线程信息,但为什么和代码中打印出来的进程号不一致呢?
【Azure Developer】Windows中通过pslist命令查看到Java进程和线程信息,但为什么和代码中打印出来的进程号不一致呢?
101 1
|
10月前
|
API Python Windows
python3应用windows api对后台程序窗口及桌面截图并保存的方法
python3应用windows api对后台程序窗口及桌面截图并保存的方法
631 1
|
10月前
|
安全 Java API
Java 8中的Stream API:简介与实用指南深入理解Java并发编程:线程安全与锁优化
【5月更文挑战第29天】本文旨在介绍Java 8中引入的Stream API,这是一种用于处理集合的新方法。我们将探讨Stream API的基本概念,以及如何使用它来简化集合操作,提高代码的可读性和效率。 【5月更文挑战第29天】 在Java并发编程中,线程安全和性能优化是两个核心议题。本文将深入探讨如何通过不同的锁机制和同步策略来保证多线程环境下的数据一致性,同时避免常见的并发问题如死锁和竞态条件。文章还将介绍现代Java虚拟机(JVM)针对锁的优化技术,包括锁粗化、锁消除以及轻量级锁等概念,并指导开发者如何合理选择和使用这些技术以提升应用的性能。
|
9月前
|
安全 API C++
逆向学习Windows篇:C++中多线程的使用和回调函数的实现
逆向学习Windows篇:C++中多线程的使用和回调函数的实现
306 0
|
10月前
|
Linux API C++
【Linux C/C++ 线程同步 】Linux API 读写锁的编程使用
【Linux C/C++ 线程同步 】Linux API 读写锁的编程使用
95 1

热门文章

最新文章