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

目录
相关文章
|
2月前
|
调度 Windows
|
1月前
|
安全 API C++
逆向学习Windows篇:C++中多线程的使用和回调函数的实现
逆向学习Windows篇:C++中多线程的使用和回调函数的实现
25 0
|
2月前
|
安全 Java API
Java 8中的Stream API:简介与实用指南深入理解Java并发编程:线程安全与锁优化
【5月更文挑战第29天】本文旨在介绍Java 8中引入的Stream API,这是一种用于处理集合的新方法。我们将探讨Stream API的基本概念,以及如何使用它来简化集合操作,提高代码的可读性和效率。 【5月更文挑战第29天】 在Java并发编程中,线程安全和性能优化是两个核心议题。本文将深入探讨如何通过不同的锁机制和同步策略来保证多线程环境下的数据一致性,同时避免常见的并发问题如死锁和竞态条件。文章还将介绍现代Java虚拟机(JVM)针对锁的优化技术,包括锁粗化、锁消除以及轻量级锁等概念,并指导开发者如何合理选择和使用这些技术以提升应用的性能。
|
2月前
|
API Python Windows
python3应用windows api对后台程序窗口及桌面截图并保存的方法
python3应用windows api对后台程序窗口及桌面截图并保存的方法
249 1
|
2月前
|
Linux API C++
【Linux C/C++ 线程同步 】Linux API 读写锁的编程使用
【Linux C/C++ 线程同步 】Linux API 读写锁的编程使用
31 1
|
7月前
|
监控 安全 API
6.9 Windows驱动开发:内核枚举进线程ObCall回调
在笔者上一篇文章`《内核枚举Registry注册表回调》`中我们通过特征码定位实现了对注册表回调的枚举,本篇文章`LyShark`将教大家如何枚举系统中的`ProcessObCall`进程回调以及`ThreadObCall`线程回调,之所以放在一起来讲解是因为这两中回调在枚举是都需要使用通用结构体`_OB_CALLBACK`以及`_OBJECT_TYPE`所以放在一起来讲解最好不过。
94 1
6.9 Windows驱动开发:内核枚举进线程ObCall回调
|
2月前
|
Java API 调度
Java多线程基础(线程与进程的区别,线程的创建方式及常用api,线程的状态)
Java多线程基础(线程与进程的区别,线程的创建方式及常用api,线程的状态)
65 0
Java多线程基础(线程与进程的区别,线程的创建方式及常用api,线程的状态)
|
7月前
|
网络协议 安全 API
9.9 Windows驱动开发:内核远程线程实现DLL注入
在笔者上一篇文章`《内核RIP劫持实现DLL注入》`介绍了通过劫持RIP指针控制程序执行流实现插入DLL的目的,本章将继续探索全新的注入方式,通过`NtCreateThreadEx`这个内核函数实现注入DLL的目的,需要注意的是该函数在微软系统中未被导出使用时需要首先得到该函数的入口地址,`NtCreateThreadEx`函数最终会调用`ZwCreateThread`,本章在寻找函数的方式上有所不同,前一章通过内存定位的方法得到所需地址,本章则是通过解析导出表实现。
101 0
9.9 Windows驱动开发:内核远程线程实现DLL注入
|
7月前
|
监控 安全 API
7.1 Windows驱动开发:内核监控进程与线程回调
在前面的文章中`LyShark`一直在重复的实现对系统底层模块的枚举,今天我们将展开一个新的话题,内核监控,我们以`监控进程线程`创建为例,在`Win10`系统中监控进程与线程可以使用微软提供给我们的两个新函数来实现,此类函数的原理是创建一个回调事件,当有进程或线程被创建或者注销时,系统会通过回调机制将该进程相关信息优先返回给我们自己的函数待处理结束后再转向系统层。
87 0
7.1 Windows驱动开发:内核监控进程与线程回调
|
7月前
|
监控 Windows
4.4 Windows驱动开发:内核监控进程与线程创建
当你需要在Windows操作系统中监控进程的启动和退出时,可以使用`PsSetCreateProcessNotifyRoutineEx`函数来创建一个`MyCreateProcessNotifyEx`回调函数,该回调函数将在每个进程的创建和退出时被调用。PsSetCreateProcessNotifyRoutineEx 用于在系统启动后向内核注册一个回调函数,以监视新进程的创建和退出,
57 0
4.4 Windows驱动开发:内核监控进程与线程创建