多线程实现线程同步——事件对象

事件对象是指在程序中使用内核对象的有无信号状态实现线程的同步。

1.使用API函数操作事件对象

API函数为CreateEvent;

函数原型为:

HANDLE CreateEvent(  LPSECURITY_ATTRIBUTES lpEventAttributes, // SD
  BOOL bManualReset,                       // reset type
  BOOL bInitialState,                      // initial state
  LPCTSTR lpName                           // object name);

参数lpEventAttributes是结构体SECURITY_ATTRIBUTES 的指针,表示新创建的事件对象的安全属性。如果设为NULL, 则使用默认安全属性。

参数bManualReset表示所创建的事件对象是人工重置还是自动重置。如果该参数为true,则表示程序所创建的事件对象为人工重置,如果为false,则表示创建的事件对象为自动重置。

参数bInitialState表示事件对象的初始状态。如果该参数为true,则表示事件对象初始时为有信号状态,否则,为无信状态。

参数npName表示事件对象的名称。如果该参数为NULL,则表示程序创建的是一个匿名的事件对象。

使用WaitForSingleObject主动请求事件对象。

DWORD WaitForSingleObject(  HANDLE hHandle,        // handle to object
  DWORD dwMilliseconds   // time-out interval);

参数dwMilliseconds表示该函数将在事件对象上的等待时间,如果为INFINITE,则函数永远等待。

使用SetEvent将指定的事件对象设置为有信号状态。使用ResetEvent将指定的事件对象设置为无信号状态。

BOOL SetEvent(  HANDLE hEvent   // handle to event);
BOOL ResetEvent(  HANDLE hEvent   // handle to event);

下面是C语言实现的代码:

#include <stdio.h>
#include <windows.h>
DWORD WINAPI myfun1(LPVOID lpParameter);                    //声明线程函数
DWORD WINAPI myfun2(LPVOID lpParameter);

HANDLE hevent;                                               //定义全局变量hevent
int a = 0;
int main()
{
	HANDLE h1, h2;
	hevent = ::CreateEvent(NULL, FALSE, false, NULL);
	::SetEvent(hevent);
	h1 = ::CreateThread(NULL, 0, myfun1, NULL, 0, NULL);     //创建线程
	printf("线程1开始运行!\r\n");
	h2 = ::CreateThread(NULL, 0, myfun2, NULL, 0, NULL);
	printf("线程2开始运行!\r\n");
	::CloseHandle(h1);
	::CloseHandle(h2);
	::Sleep(10000);
	return 0;
}

DWORD WINAPI myfun1(LPVOID lpParameter)                      //线程函数1
{
	while(1)
	{
		::WaitForSingleObject(hevent, INFINITE);             //请求事件对象
		::ResetEvent(hevent);                                //设置事件对象为无信号状态
		if(a < 1000)
		{
			a += 1;
			::Sleep(1000);
			printf("线程1正在计数%d\r\n", a);
			::SetEvent(hevent);                               //设置事件对象为有信号状态
		}
		else
		{
			::SetEvent(hevent);
			break;
		}
	}
	return 0;
}
DWORD WINAPI myfun2(LPVOID lpParameter)
{
	while(1)
	{
		::WaitForSingleObject(hevent, INFINITE);
		::ResetEvent(hevent);
		if(a < 1000)
		{
			a += 1;
			::Sleep(1000);
			printf("线程2正在计数%d\r\n", a);
			::SetEvent(hevent);
		}
		else
		{
			::SetEvent(hevent);
			break;
		}
	}
	return 0;
}

结果:

2.使用CEvent类实现线程同步

CEvent函数原型:

CEvent( BOOL bInitiallyOwn = FALSE, BOOL bManualReset = FALSE, LPCTSTR lpszName = NULL, LPSECURITY_ATTRIBUTES lpsaAttribute = NULL );

参数bInitiallyOwn表示事件对象的初始化状态。如果为true,则表示事件对象为有信号状态,否则,为无信号状态,默认为无信号状态。

参数bManualReset表示该事件对象是人工重置还是自动重置。如果该参数为true,则事件对象为人工重置,否则,为自动重置。

参数bpsName表示该事件对象的命名。默认为NULL。

参数bpsaAttribute表示事件对象的安全属性。一般指定为默认安全属性。

下面是C语言实现的代码:

#include <stdio.h>
#include <afxmt.h>                                           //头文件,不是windows.h

DWORD WINAPI myfun1(LPVOID lpParameter);                     //声明线程函数
DWORD WINAPI myfun2(LPVOID lpParameter);
CEvent event;
int a = 0;

int main()
{
	CEvent(false, false, NULL, NULL);
	HANDLE h1, h2;
	CreateEvent(NULL, FALSE, false, NULL);
	event.SetEvent();
	h1 = ::CreateThread(NULL, 0, myfun1, NULL, 0, NULL);      //创建线程
	printf("线程1开始运行!\r\n");
	h2 = ::CreateThread(NULL, 0, myfun2, NULL, 0, NULL);
	printf("线程2开始运行!\r\n");
	::CloseHandle(h1);                                         //关闭线程句柄对象
	::CloseHandle(h2);
	::Sleep(10000);
	return 0;
}

DWORD WINAPI myfun1(LPVOID lpParameter)                      //线程函数1
{
	while(1)
	{
		::WaitForSingleObject(event.m_hObject, INFINITE);        //请求事件对象
		event.ResetEvent();
		if(a < 1000)                                             //设置事件对象为无信号状态
		{
			a += 1;
			::Sleep(1000);
			printf("线程1正在计数%d\r\n", a);
			event.SetEvent();                                  //设置事件对象为有信号状态
		}
		else
		{
			event.SetEvent();
			break;
		}
	}
	return 0;
}
DWORD WINAPI myfun2(LPVOID lpParameter)
{
	while(1)
	{
		::WaitForSingleObject(event.m_hObject, INFINITE);
		event.ResetEvent();
		if(a < 1000)
		{
			a += 1;
			::Sleep(1000);
			printf("线程2正在计数%d\r\n", a);
			event.SetEvent();
		}
		else
		{
			event.SetEvent();
			break;
		}
	}
	return 0;
}

结果:

时间: 2024-10-16 09:53:56

多线程实现线程同步——事件对象的相关文章

转--- 秒杀多线程第六篇 经典线程同步 事件Event

阅读本篇之前推荐阅读以下姊妹篇: <秒杀多线程第四篇 一个经典的多线程同步问题> <秒杀多线程第五篇 经典线程同步关键段CS> 上一篇中使用关键段来解决经典的多线程同步互斥问题,由于关键段的“线程所有权”特性所以关键段只能用于线程的互斥而不能用于同步.本篇介绍用事件Event来尝试解决这个线程同步问题. 首先介绍下如何使用事件.事件Event实际上是个内核对象,它的使用非常方便.下面列出一些常用的函数. 第一个 CreateEvent 函数功能:创建事件 函数原型: HANDLEC

秒杀多线程第六篇 经典线程同步 事件Event

阅读本篇之前推荐阅读以下姊妹篇: <秒杀多线程第四篇 一个经典的多线程同步问题> <秒杀多线程第五篇 经典线程同步关键段CS> 上一篇中使用关键段来解决经典的多线程同步互斥问题,由于关键段的"线程所有权"特性所以关键段只能用于线程的互斥而不能用于同步.本篇介绍用事件Event来尝试解决这个线程同步问题. 首先介绍下如何使用事件.事件Event实际上是个内核对象,它的使用非常方便.下面列出一些常用的函数. 第一个 CreateEvent 函数功能:创建事件 函数原

线程同步——内核对象实现线程同步——事件内核对象

1 事件内核对象 2 3 事件类型对象有两种不同类型,手动重置和自动重置 4 手动重置:当一个手动重置对象被触发时候,等待该对象的所有线程变为可调度. 5 自动重置:当一个自动重置对象被触发时,只有一个等待该事件的线程会变为可调度 6 7 下面是一个创建事件内核对象的函数: 8 HANDLE CreateEvent( 9 LPSECURITY_ATTRIBUTES lpEventAttributes, 10 BOOL bManualReset, 11 BOOL bInitialState, 12

mfc小工具开发之定时闹钟之---多线程急线程同步

一.MFC对多线程编程的支持 MFC中有两类线程,分别称之为工作者线程和用户界面线程.二者的主要区别在于工作者线程没有消息循环,而用户界面线程有自己的消息队列和消息循环. 工作者线程没有消息机制,通常用来执行后台计算和维护任务,如冗长的计算过程,打印机的后台打印等.用户界面线程一般用于处理独立于其他线程执行之外的用户输入,响应用户及系统所产生的事件和消息等.但对于Win32的API编程而言,这两种线程是没有区别的,它们都只需线程的启动地址即可启动线程来执行任务. 在MFC中,一般用全局函数Afx

MFC——9.多线程与线程同步

Lesson9:多线程与线程同步 程序.进程和线程是操作系统的重点,在计算机编程中,多线程技术是提高程序性能的重要手段.本文主要讲解操作系统中程序.进程和线程之间的关系,并通过互斥对象和事件对象实例说明多线程和线程同步技术. 1.      程序.进程和线程 1.1  程序和进程 程序是计算机指令的集合,它以文件的形式存储在磁盘上.进程通常被定义为一个正在运行的程序的实例,是一个程序在其自身的地址空间中的一次执行活动.进程是资源申请.调度和独立运行的单位,因此,它使用系统中的运行资源:而程序不能

java多线程之 ---- 线程同步

java多线程之线程同步 线程同步 定义:同步是指在同一时间段内只能运行一个线程. 分类:同步方法.同步块. 作用:安全解决共享问题. 同步块: 语法: synchronized (同步对象) { 需要同步的代码; } 例子: public class ThreadDemo implements Runnable{ private int ticket = 5; public void run(){ for(int i=1;i<=5;i++){ synchronized (this){ if(t

线程同步——内核对象实现线程同步——等待函数

1 对于内核对象实现线程同步,不得不提三点: 2 1)大多数内核对象既有触发也有未触发两个状态 3 比如:进程.线程.作业.文件流.事件.可等待的计时器.信号量.互斥量 4 2)等待函数:等待函数使线程自愿进入等待状态,直到指定的内核对象变为触发状态为止, 5 说道等待我们最喜欢不过了,因为这样不会浪费我们宝贵的CPU时间. 6 3)对于自动重置对象来说,当对象被触发时,函数会自动检测到(手动重置对象为触发是,函数也能检测到), 7 并开始执行,但是在函数会在返回之前使事件变为非触发状态. 8

Linux程序设计学习笔记----多线程编程线程同步机制之互斥量(锁)与读写锁

互斥锁通信机制 基本原理 互斥锁以排他方式防止共享数据被并发访问,互斥锁是一个二元变量,状态为开(0)和关(1),将某个共享资源与某个互斥锁逻辑上绑定之后,对该资源的访问操作如下: (1)在访问该资源之前需要首先申请互斥锁,如果锁处于开状态,则申请得到锁并立即上锁(关),防止其他进程访问资源,如果锁处于关,则默认阻塞等待. (2)只有锁定该互斥锁的进程才能释放该互斥锁. 互斥量类型声明为pthread_mutex_t数据类型,在<bits/pthreadtypes.h>中有具体的定义. 互斥量

Win32线程同步内核对象的比较

X86处理器上用户层到内核层的转换要花费600个CPU指令周期 临界区(关键代码段)不是内核对象 但当访问被占用的资源时会使用内核资源 功能同互斥但不可跨进程 (以上引用自:http://www.dewen.org/q/9561) WIN32内核对象都是由HANDLE操控 信号量(Semaphore) wait函数族使访问计数递减 当且仅当访问计数0时无信号 ReleaseSemaphore递增访问计数 互斥(Mutex) 有且仅有1个访问计数的信号量(二元信号量binary semaphore