C++中Event使用

标签: c++nullattributeswinapiobjectthread
  5049人阅读  评论(0)  收藏  举报

转载自:http://www.cnblogs.com/yuanzfy/archive/2011/08/26/2154460.html

之前线程同步用互斥锁Mutex或用户模式的CriticalSection等来进行同步,而且使用效果一直很好,直到最近遇到新问题,朋友推荐用事件去处理。但是对事件了解比较少,所以摘了篇文章看,另外自己做了下试验(所以代码不是转的哦)。

概念:

事件是用来同步地位不相等的线程的,事件可以用来使一个线程完成一件事情,然后另外的线程完成剩下的事情。

事件的使用很灵活,自动事件的激发态是由人工来控制的(超级重要,尤其是在需要精确掌控是否处于有信号状态的时候),而Mutex在释放(releaseMetux)后就一直处于激发态,直到线程WaitForSingleObject。事件可以用来控制经典的读写模型和生产者和消费者模型。相应的方式为,生成者等待消费者的消费,再消费者消费完后通知生产者进行生产。

Mutex是排他的占有资源,一般用于地位相等的线程进行同步。每个线程都可以排他的访问一个资源或代码段,不存在哪个线程对资源访问存在优先次序。一个线程只能在Mutex处于激发态的时候访问被保护的资源或代码段,线程可以通过WaitForSingelObject来等待Mutex,在访问资源完成之后,ReleaseMutex释放Mutex,此时Mutex处于激发态。

注意:对句柄使用WaitForSIngleObject()之后的副作用(句柄状态的自动变化)

Mutex具有成功等待的副作用,在用WaitForSingleObject()等待到Mutex后,Mutex自动变为无信号状态,直到调用ReleaseMutex()使Mutex变为有信号状态为止;

自动事件也具有成功等待的副作用;

手动事件没有,必须调用ResetEvent()使手动事件变为未激发态;

进程和线程也没有成功等待的副作用。当线程或者进程函数返回时,线程内核对象变为激发态,但WaitForSingleObject并没有使线程或者进程的内核对象变为未激发态。

总之,事件一般用于控制线程的先后顺序,而Mutex一般用于排他的访问资源。

Event的使用:

首先创建事件:

HANDLE CreateEvent(

  LPSECURITY_ATTRIBUTES lpEventAttributes, // 安全属性

  BOOL bManualReset, // 复位方式,1为手动复位,0为自动复位

  BOOL bInitialState, // 初始状态,0为不可用状态即无信号,1为可用状态即有信号

  LPCTSTR lpName // 对象名称

  );

SetEvent()设置事件为有信号;ResetEvent()设置事件为无信号。

WaitForSingleObject()来等待Event变为有信号:

DWORD WaitForSignalObject(HANDLE hObject, DWORD dwMilliseconds);

返回值有以下几种:

WAIT_OBJECT_0 :表示等待对象已经变为有信号状态,如果设置为自动复位,还会把此信号再次变为无信号状态。

WAIT_TIMEOUT   :表示等待超时

WAIT_FAILED      :表示等待对象句柄是一个无效句柄。

代码示例:

功能:用主线程来等待子线程的执行结束

[cpp]  view plain  copy
  1. HANDLE hEvent;  
  2. int num=1;  
  3.   
  4. DWORD WINAPI _threadProc(LPVOID lpParam)  
  5. {  
  6.     for(int i=0; i<10000; i++)  
  7.     {  
  8.         for(int j=0; j<10000; j++)  
  9.             ;  
  10.     }  
  11.   
  12.     num=10;  
  13.     SetEvent(hEvent);  
  14.     return 0;  
  15. }  
  16.   
  17. void main()  
  18. {  
  19.     //手动复位,初始时无信号  
  20.     hEvent=CreateEvent(NULL, TRUE, FALSE, NULL);  
  21.     if(hEvent==NULL)  
  22.     {     
  23.         printf("hEvent is null\n");  
  24.         return;  
  25.     }  
  26.   
  27.     HANDLE hThread=CreateThread(NULL, 0, _threadProc, NULL, 0, NULL);  
  28.   
  29.     DWORD dwRet=WaitForSingleObject(hEvent, INFINITE);  
  30.     if(dwRet==WAIT_ABANDONED)  
  31.         printf("WAIT_ABANDONED\n");  
  32.     else if(dwRet==WAIT_TIMEOUT)  
  33.         printf("WAIT_TIMEOUT\n");  
  34.     else if(dwRet==WAIT_OBJECT_0)  
  35.         printf("有信号状态\n");  
  36.     else if(dwRet==WAIT_FAILED)  
  37.         printf("WAIT_FAILED\n");  
  38.   
  39.     printf("sub thread run out, num is %d\n", num);  
在 Qt ,可以通过重写 `QWidget` 的 `event` 函数来拦截和处理各种事件,包括 `mousePressEvent` 事件。在 `event` 函数,我们可以判断事件类型,如果是 `mousePressEvent` 事件,则进行处理并返回 `true`,否则交给父类处理。 下面是一个使用 `event` 函数拦截 `mousePressEvent` 事件的示例代码: ```cpp class MyWidget : public QWidget { public: MyWidget(QWidget *parent = nullptr) : QWidget(parent) { setFixedSize(200, 200); } protected: bool event(QEvent *event) override { if (event->type() == QEvent::MouseButtonPress) { QMouseEvent *mouseEvent = static_cast<QMouseEvent *>(event); if (mouseEvent->button() == Qt::LeftButton) { qDebug() << "Left button pressed!"; // 在此添加处理代码 return true; } } return QWidget::event(event); } }; ``` 在上面的代码,我们重写了 `event` 函数,判断事件类型是否为 `mousePressEvent`,并且判断鼠标按键是否为左键。如果是左键按下,则输出信息并进行处理,返回 `true` 表示事件已经被处理完毕,不需要再传递给父类处理。 需要注意的是,在 `event` 函数,我们需要使用 `static_cast` 将 `QEvent` 类型的指针转换为 `QMouseEvent` 类型的指针,才能访问到鼠标事件的具体信息。 此外,还可以通过重写 `mousePressEvent` 函数来处理鼠标点击事件,如下所示: ```cpp class MyWidget : public QWidget { public: MyWidget(QWidget *parent = nullptr) : QWidget(parent) { setFixedSize(200, 200); } protected: void mousePressEvent(QMouseEvent *event) override { if (event->button() == Qt::LeftButton) { qDebug() << "Left button pressed!"; // 在此添加处理代码 } else { QWidget::mousePressEvent(event); } } }; ``` 在上面的代码,我们重写了 `mousePressEvent` 函数,判断鼠标按键是否为左键。如果是左键按下,则输出信息并进行处理,否则交给父类处理。这种方式更加简单明了,但是无法拦截和处理其他类型的事件。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值