Linux平台用C++实现事件对象,同步线程(转)

本文属于转载,原文链接如下:http://blog.csdn.net/chexlong/article/details/7080537

与其相关的一组API包括:pthread_mutex_init,pthread_cond_init,pthread_mutex_lock,pthread_cond_wait,pthread_mutex_unlock,pthread_cond_broadcast,pthread_cond_timedwait,pthread_cond_destroy,pthread_mutex_destroy。

MyEvent.h

#ifndef My_Event_Header
#define My_Event_Header

#include <iostream>
#include <pthread.h>
#include <errno.h>

using namespace std;

//---------------------------------------------------------------

class CEventImpl
{
protected:

    /*
     动态方式初始化互斥锁,初始化状态变量m_cond
    `bAutoReset  true   人工重置
                 false  自动重置
    */
    CEventImpl(bool manualReset);        

    /*
     注销互斥锁,注销状态变量m_cond
    */
    ~CEventImpl();

    /*
     将当前事件对象设置为有信号状态
     若自动重置,则等待该事件对象的所有线程只有一个可被调度
     若人工重置,则等待该事件对象的所有线程变为可被调度
    */
    void SetImpl();

    /*
     以当前事件对象,阻塞线程,将其永远挂起
     直到事件对象被设置为有信号状态
    */
    bool WaitImpl();

    /*
     以当前事件对象,阻塞线程,将其挂起指定时间间隔
     之后线程自动恢复可调度
    */
    bool WaitImpl(long milliseconds);

    /*
     将当前事件对象设置为无信号状态
    */
    void ResetImpl();

private:
    bool            m_manual;
    volatile bool   m_state;
    pthread_mutex_t m_mutex;
    pthread_cond_t  m_cond;
};

inline void CEventImpl::SetImpl()
{
    if (pthread_mutex_lock(&m_mutex))
        cout<<"cannot signal event (lock)"<<endl;

    //设置状态变量为true,对应有信号
    m_state = true;

    //cout<<"CEventImpl::SetImpl m_state = "<<m_state<<endl;

    //重新激活所有在等待m_cond变量的线程
    if (pthread_cond_broadcast(&m_cond))
    {
        pthread_mutex_unlock(&m_mutex);
        cout<<"cannot signal event"<<endl;
    }
    pthread_mutex_unlock(&m_mutex);
}

inline void CEventImpl::ResetImpl()
{
    if (pthread_mutex_lock(&m_mutex))
        cout<<"cannot reset event"<<endl;

    //设置状态变量为false,对应无信号
    m_state = false;

    //cout<<"CEventImpl::ResetImpl m_state = "<<m_state<<endl;

    pthread_mutex_unlock(&m_mutex);
}

//---------------------------------------------------------------

class CMyEvent: private CEventImpl
{
public:
    CMyEvent(bool bManualReset = true);
    ~CMyEvent();

    void Set();
    bool Wait();
    bool Wait(long milliseconds);
    bool TryWait(long milliseconds);
    void Reset();

private:
    CMyEvent(const CMyEvent&);
    CMyEvent& operator = (const CMyEvent&);
};

inline void CMyEvent::Set()
{
    SetImpl();
}

inline bool CMyEvent::Wait()
{
    return WaitImpl();
}

inline bool CMyEvent::Wait(long milliseconds)
{
    if (!WaitImpl(milliseconds))
    {
        cout<<"time out"<<endl;
        return false;
    }
    else
    {
        return true;
    }
}

inline bool CMyEvent::TryWait(long milliseconds)
{
    return WaitImpl(milliseconds);
}

inline void CMyEvent::Reset()
{
    ResetImpl();
}

#endif

MyEvent.cpp

#include "MyEvent.h"
#include <sys/time.h>

CEventImpl::CEventImpl(bool manualReset): m_manual(manualReset), m_state(false)
{
    if (pthread_mutex_init(&m_mutex, NULL))
        cout<<"cannot create event (mutex)"<<endl;
    if (pthread_cond_init(&m_cond, NULL))
        cout<<"cannot create event (condition)"<<endl;
}

CEventImpl::~CEventImpl()
{
    pthread_cond_destroy(&m_cond);
    pthread_mutex_destroy(&m_mutex);
}

bool CEventImpl::WaitImpl()
{
    if (pthread_mutex_lock(&m_mutex))
    {
        cout<<"wait for event failed (lock)"<<endl;
        return false;
    }
    while (!m_state)
    {
        //cout<<"CEventImpl::WaitImpl while m_state = "<<m_state<<endl;

        //对互斥体进行原子的解锁工作,然后等待状态信号
        if (pthread_cond_wait(&m_cond, &m_mutex))
        {
            pthread_mutex_unlock(&m_mutex);
            cout<<"wait for event failed"<<endl;
            return false;
        }
    }
    if (m_manual)
        m_state = false;
    pthread_mutex_unlock(&m_mutex);

    //cout<<"CEventImpl::WaitImpl end m_state = "<<m_state<<endl;

    return true;
}

bool CEventImpl::WaitImpl(long milliseconds)
{
    int rc = 0;
    struct timespec abstime;
    struct timeval tv;
    gettimeofday(&tv, NULL);
    abstime.tv_sec  = tv.tv_sec + milliseconds / 1000;
    abstime.tv_nsec = tv.tv_usec*1000 + (milliseconds % 1000)*1000000;
    if (abstime.tv_nsec >= 1000000000)
    {
        abstime.tv_nsec -= 1000000000;
        abstime.tv_sec++;
    }

    if (pthread_mutex_lock(&m_mutex) != 0)
    {
        cout<<"wait for event failed (lock)"<<endl;
        return false;
    }
    while (!m_state)
    {
        //自动释放互斥体并且等待m_cond状态,并且限制了最大的等待时间
        if ((rc = pthread_cond_timedwait(&m_cond, &m_mutex, &abstime)))
        {
            if (rc == ETIMEDOUT) break;
            pthread_mutex_unlock(&m_mutex);
            cout<<"cannot wait for event"<<endl;
            return false;
        }
    }
    if (rc == 0 && m_manual)
        m_state = false;
    pthread_mutex_unlock(&m_mutex);
    return rc == 0;
}

CMyEvent::CMyEvent(bool bManualReset): CEventImpl(bManualReset)
{
}

CMyEvent::~CMyEvent()
{
}

测试代码如下所示:pthread_event.cpp

// pthread_event.cpp : 定义控制台应用程序的入口点。
//

#include <unistd.h>
#include "MyEvent.h"

#define PRINT_TIMES 10

//创建一个人工自动重置事件对象
CMyEvent g_myEvent;
int g_iNum = 0;

//线程函数1
void * ThreadProc1(void *pParam)
{
    for (int i = 0; i < PRINT_TIMES; i++)
    {
        g_iNum++;
        cout<<"ThreadProc1 do print, Num = "<<g_iNum<<endl;

        //设置事件为有信号状态
        g_myEvent.Set();

        sleep(1);
    }

    return (void *)0;
}

//线程函数2
void * ThreadProc2(void *pParam)
{
    bool bRet = false;
    while ( 1 )
    {
        if ( g_iNum >= PRINT_TIMES )
        {
            break;
        }

        //以当前事件对象阻塞本线程,将其挂起
        bRet = g_myEvent.Wait();
        if ( bRet )
        {
            cout<<"ThreadProc2 do print, Num = "<<g_iNum<<endl;

            //设置事件为无信号状态
            g_myEvent.Reset();
        }
        else
        {
            cout<<"ThreadProc2 system exception"<<endl;
        }
    }

    return (void *)0;
}

int main(int argc, char* argv[])
{
    pthread_t thread1,thread2;
    pthread_attr_t attr1,attr2;

    //创建两个工作线程
    pthread_attr_init(&attr1);
    pthread_attr_setdetachstate(&attr1,PTHREAD_CREATE_JOINABLE);
    if (pthread_create(&thread1,&attr1, ThreadProc1,NULL) == -1)
    {
        cout<<"Thread 1: create failed"<<endl;
    }
    pthread_attr_init(&attr2);
    pthread_attr_setdetachstate(&attr2,PTHREAD_CREATE_JOINABLE);
    if (pthread_create(&thread2,&attr2, ThreadProc2,NULL) == -1)
    {
        cout<<"Thread 2: create failed"<<endl;
    }

    //等待线程结束
    void *result;
    pthread_join(thread1,&result);
    pthread_join(thread2,&result);

    //关闭线程,释放资源
    pthread_attr_destroy(&attr1);
    pthread_attr_destroy(&attr2);

    int iWait;
    cin>>iWait;

    return 0;
}

编译运行结果如下所示:

时间: 2024-10-25 15:15:54

Linux平台用C++实现事件对象,同步线程(转)的相关文章

【同步】孙鑫VC++笔记-事件对象同步

事件对象同步 //CreateEvent设置自定的,并且初始有信号#include<windows.h> #include<iostream.h> DWORD WINAPI ThreadProc1( LPVOID lpParameter ); DWORD WINAPI ThreadProc2( LPVOID lpParameter ); int tickes=100; HANDLE g_hEvent; int main() { HANDLE hThread1=CreateThrea

临界区,互斥量,信号量,事件的区别(线程同步)

(转)临界区,互斥量,信号量,事件的区别(线程同步) (转)临界区,互斥量,信号量,事件的区别(线程同步) . 分类: C++ windows 核心编程 2012-04-10 14:55 3321人阅读 评论(0) 收藏 举报 semaphoremfcnulleventsthreadhttp服务器 四种进程或线程同步互斥的控制方法 1.临界区:通过对多线程的串行化来访问公共资源或一段代码,速度快,适合控制数据访问. 2.互斥量:为协调共同对一个共享资源的单独访问而设计的. 3.信号量:为控制一个

(转)临界区,互斥量,信号量,事件的区别(线程同步)

(转)临界区,互斥量,信号量,事件的区别(线程同步) 分类: C++ windows 核心编程 2012-04-10 14:55 2064人阅读 评论(0) 收藏 举报 semaphore mfc null events thread http服务器 四种进程或线程同步互斥的控制方法 1.临界区:通过对多线程的串行化来访问公共资源或一段代码,速度快,适合控制数据访问. 2.互斥量:为协调共同对一个共享资源的单独访问而设计的. 3.信号量:为控制一个具有有限数量用户资源而设计. 4.事 件:用来通

VC++深入详解——16章:线程同步,事件对象

这章介绍另外:事件对象和关键代码段. 进程相关函数: CreateEvent函数: 第一个参数:安全属性,默认的安全属性为NULL 第二个参数:复位方式, 人工设置为TRUE,自动设置为FALSE, 当为人工设置时,等待事件的线程时,需要resetevent函数来设置其为无型号状态. 第三个参数:初始状态:TRUE为有信号状态,FALSE为无信号状态. 第四个参数:对象名称,NULL为匿名名称. 创建或打开一个命名或匿名的事件对象(也属于内核对象) 返回:返回的是事件对象的句柄. SetEven

windows下多线程同步(利用事件对象,互斥对象,关键代码段)实现

一:利用事件实现线程同步 1.createthread函数的用法 hThread = CreateThread(&security_attributes, dwStackSize, ThreadProc,pParam, dwFlags, &idThread) ; HANDLE CreateThread( LPSECURITY_ATTRIBUTES lpThreadAttributes, DWORD dwStackSize, LPTHREAD_START_ROUTINE lpStartAdd

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

事件对象是指在程序中使用内核对象的有无信号状态实现线程的同步. 1.使用API函数操作事件对象 API函数为CreateEvent: 函数原型为: HANDLE CreateEvent( LPSECURITY_ATTRIBUTES lpEventAttributes, // SD BOOL bManualReset, // reset type BOOL bInitialState, // initial state LPCTSTR lpName // object name); 参数lpEve

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

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

嵌入式 Linux进程间通信(十二)——多线程同步

嵌入式 Linux进程间通信(十二)--多线程同步 多线程编程中有三种线程同步机制:互斥锁.信号量.条件量.本文将使用生产者消费者问题编程实践三种线程同步方式. 生产者.消费者问题:生产者线程生产物品,然后将物品放置在一个空缓冲区中供消费者线程消费.消费者线程从缓冲区中获得物品,然后释放缓冲区.当生产者线程生产物品时,如果没有空缓冲区可用,那么生产者线程必须等待消费者线程释放出一个空缓冲区.当消费者线程消费物品时,如果没有满的缓冲区,那么消费者线程将被阻塞,直到新的物品被生产出来. 一.互斥锁

Linux平台(Centos7)-lnmp一键式部署mysql,nginx,php,php-fpm服务

Linux平台(Centos7)-lnmp一键式部署mysql,nginx,php,php-fpm服务 1. 部署方式1:手动部署. 6 1.1. 配置防火墙. 6 1.2. 关闭firewall 6 1.3. 安装iptables防火墙. 6 1.4. 安装Apache 7 1.5. 安装MariaDB 9 1.5.1. 安装MariaDB 9 1.5.2. 启动服务. 10 1.5.3. 设置开机启动. 10 1.5.4. 为root账户设置密码. 11 1.5.5. 重启MariaDB 1