使用Event对象进行多线程处理 [英] Multithreading with Event object

查看:78
本文介绍了使用Event对象进行多线程处理的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这是一段实验多线程的代码。

当我按下按钮时_StartThread()函数被执行。

第一次推送后第一个线程被启动并且它每行写一行,在行的末尾加上1> 1。

第二次推送后,第二个线程启动,并在最后写入2> 2的行。

我看到程序继续用1> 1写一行,然后在末尾写一行2> 2,我想我使用WaitForSingleObject(),ResetEvent进行同步()和SetEvent()以适当的方式。

但在一些行后,程序混合了消息末尾的数字,我得到1> 2和2> 1,并且我开始认为我没有以正确的方式使用同步功能。这是真的吗?



 LONG CTestMsgDlg :: m_nWorking =  0 ; 
HANDLE CTestMsgDlg :: m_hevent;

CTestMsgDlg :: CTestMsgDlg(CWnd * pParent / * = NULL * /
:CDialog(CTestMsgDlg :: IDD,pParent)
{
// {{AFX_DATA_INIT(CTestMsgDlg)
// }} AFX_DATA_INIT
m_hevent = CreateEvent(NULL,TRUE,TRUE,_T( hevenim)); // 手动重置,初始化信号
}

void CTestMsgDlg :: _ St​​artThread()
{
// :: InterlockedExchange(& m_nWorking,1);
CWinThread * pThread;
m_nWorking + = 1 ;
pThread = AfxBeginThread(& CTestMsgDlg :: WorkerThread,m_hWnd,THREAD_PRIORITY_NORMAL);
}

UINT AFX_CDECL CTestMsgDlg :: WorkerThread(LPVOID lpParam)
// 静态函数
{
int v2 = m_nWorking;
int v4;
long v5;
DWORD rwait;
BOOL事件集;
while (m_nWorking)
{
CString * pString = new CString的;
DWORD dwThreadID = :: GetCurrentThreadId();
SYSTEMTIME st = { 0 };
:: GetLocalTime(& st);

rwait = WaitForSingleObject(m_hevent, 9999 );

eventset = ResetEvent(m_hevent);

if (!eventset) return 0 ;
v9 = v2;
for (v4 = 1 ; v4< 222222222; v4 ++)v5 = v4 * v4 / (v4 + 1);
pString->格式(_T( 线程%X发布于%02u:%02u:% 02u:%03u%02d>%X),
dwThreadID,st.wHour,st.wMinute,st.wSecond,st.wMilliseconds,v9,v2);

eventset = SetEvent(m_hevent);

if (!eventset) return 0 ;
:: PostMessage((HWND)lpParam,WM_APP_TIMESTAMP, 0 ,(LPARAM)pString);
}
return 0 ;
}

解决方案

很难遵循你的所有逻辑,但这似乎是滥用事件对象。通常的模式是:等待单个对象,另一个线程设置此事件对象(使其发信号)。如果等待线程处于等待状态(操作系统关闭线程并且不会将其调度回执行直到它被唤醒),线程的信号将其唤醒,因此它继续执行。



即使你可以通过任何线程正式设置或重置一个事件,但是在同一个线程中没有任何意义。即使你需要在同一个线程等待之后重置线程,通过调用reset来执行它也是不正确的;你应该为这个线程使用自动重置选项。这是明显的原因:想象一下,在等待结束和手动模式之间的短时间内,线程的状态会发生一些其他线程对同一个事件对象做某事。线程同步原语是100%紧密的,即使对于最不可能进入同步模式的情况,它们也不会占用空间。如果使用正确。



此外,由于类似的原因,使用 eventset 看起来毫无意义。基于了解偶数对象状态的逻辑是错误的。此对象在线程之间共享,可以随时更改。真正有效的模式是:一个线程不时地等待一个事件对象。另一个线程改变了同一个事件对象的状态,这样就可以根据某些条件限制其他线程的执行。要继续讨论正确的方法,您需要解释您想要实现的目标。



-SA

Here is a piece of code that experiment multithreading.
When I push a button _StartThread() function is executed.
After the first push the first thread is launched and it writes a line every second with "1>1" at the end of the line.
After the second push the second thread is launched and it writes lines with "2>2" at the end.
I see the program keep writing a line with "1>1" and then a line with "2>2" at the end, and I suppose that I use synchronization by WaitForSingleObject(),ResetEvent() and SetEvent() in a proper way.
But after some lines the program mix the figures at the end of the message and I get "1>2" and "2>1", and I begin to think that I don’t use the synchronization function in a proper way. It is true?

LONG CTestMsgDlg::m_nWorking = 0;
HANDLE CTestMsgDlg::m_hevent;

CTestMsgDlg::CTestMsgDlg(CWnd* pParent /*=NULL*/)
	: CDialog(CTestMsgDlg::IDD, pParent)
{
	//{{AFX_DATA_INIT(CTestMsgDlg)
	//}}AFX_DATA_INIT
  m_hevent=CreateEvent(NULL,TRUE,TRUE,_T("hevenim"));  //manual reset, signaled initial
}

void CTestMsgDlg::_StartThread()
{
	//::InterlockedExchange(&m_nWorking, 1);
	CWinThread* pThread;
	m_nWorking+=1;
	 pThread = AfxBeginThread(&CTestMsgDlg::WorkerThread, m_hWnd, THREAD_PRIORITY_NORMAL);
}

UINT AFX_CDECL CTestMsgDlg::WorkerThread(LPVOID lpParam)
//static function
{
   int v2 = m_nWorking;
   int v4;
   long v5;
   DWORD rwait;
   BOOL eventset;
   while(m_nWorking)
   {
      CString* pString = new CString;
      DWORD dwThreadID = ::GetCurrentThreadId();
      SYSTEMTIME st = {0};
      ::GetLocalTime(&st);

     rwait=WaitForSingleObject(m_hevent,9999);

     eventset=ResetEvent(m_hevent);

     if (!eventset) return 0;
     v9=v2;
     for (v4=1; v4<222222222; v4++) v5=v4*v4/(v4+1) ;
     pString->Format(_T("Posted by thread %X at %02u:%02u:%02u:%03u  %02d >%X"), 
         dwThreadID, st.wHour, st.wMinute, st.wSecond, st.wMilliseconds, v9, v2);

     eventset=SetEvent(m_hevent);

     if (!eventset) return 0;
     ::PostMessage((HWND)lpParam, WM_APP_TIMESTAMP, 0, (LPARAM)pString);
   }
   return 0;
}

解决方案

It's hard to follow all your logic, but it seems like a misuse of the event object. The usual pattern is this: you wait for single object, and the other thread set this event object (make it signaled). If the waiting thread was in a wait state (OS switches the thread off and does not schedule it back to execution until it is awaken), the signalling of the thread wakes it up, so it continues execution.

Even though formally you can set or reset an event by any thread, there is no sense of doing it in the same thread. Even if you need to reset the thread after wait by the same thread, doing it by calling reset is incorrect; you should use auto-reset option for this thread instead. Is it apparent why: imagine that in the short period of time between end of wait and "manual-mode" change in the state of the thread some other thread does something to the same event object. Thread synchronization primitives are 100% tight, they don't live a room even for the least likely cases of breaking into the synchronization schema. If used correctly.

Also, using eventset looks pointless, by similar reasons. The logic based on knowing the state of the even object is wrong. This object is shared between threads and can be changed by any time. The really working pattern is this: one thread waits for an event object from time to time. Another thread changes the state of the same event object, this way throttling the execution of other thread based on some condition. To continue with the discussion of right approach, you would need to explain what exactly do you want to achieve.

—SA


这篇关于使用Event对象进行多线程处理的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆