Click here to Skip to main content
15,897,704 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
See more:
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?

C++
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;
}
Posted
Updated 1-Oct-13 2:52am
v2
Comments
[no name] 1-Oct-13 9:40am    
This does not write a line every second. It writes a line when a loop variable reaches a value. You are breaking the golden rule of not spending time in the thread function. This thread is using up all the available cpu time on one core. To write at exactly a chosen interval you should use a waitable timer to set the event (probably autoreset) on which the thread is blocking. Wasting time in the thread then setting the event as you leave the thread function is not nice.
argemi 2-Oct-13 1:18am    
This code doesn’t write a line every second, of course, that was what I have seen on the screen. About the loop: I wanted to simulate a piece of code that is not interruptible and a simple “for“ was an easy way. I don’t want to deal with waitable timer, I want to know how can I do to keep a thread running in a portion of code without been interrupted by another thread.
[no name] 2-Oct-13 1:37am    
A number of others have suggested you do some reading on multithreading. Your questions, code and comments show that you do not understand all the concepts. Without some basic understanding asking questions is pointless because you will go around in circles. By definition all code inside a thread function is (should be) interruptible. What do you think the point of multithreading is? If you run the loop long enough it has to be interrupted by other threads otherwise the program will hang. The multithreading code examples in the msdn are a very good starting point. Study these and adapt them to your needs.
argemi 2-Oct-13 2:24am    
The answer for my problem was simple: Use autoreset! Now all works fine!

1 solution

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
 
Share this answer
 
Comments
pasztorpisti 1-Oct-13 10:05am    
+5, I would recommend OP reading at least some basic threading tutorials before proceeding with writing multithreaded code...
Sergey Alexandrovich Kryukov 1-Oct-13 10:33am    
Thank you. This is a good advice.
—SA
argemi 2-Oct-13 2:01am    
Thank you for the answer and you are right about my mistake that I omitted to comment the code. This is a simple example I use to experiment multithreading. The piece of code between WaitForSingleObject() and SetEvent() is the uninterruptible code. As I said _StartThread() is launched when I push a button. This function creates a thread (defined by WorkerThread() function), so if I push the button twice I’ll have 2 threads. If the first thread is in the uninterruptible zone the second thread will wait on the WaitForSingleObject() instruction. After the first thread executes SetEvent() the second thread will continue. V2 is the “readonly” thread identification number and v9, a static variable, is the thread identification number set before the work in the uninterruptible zone begins. I think that if a task is interrupted in the uninterruptible zone the other task will modify v9 and the pString will show v2 different from v9. If the uninterruptible code isn’t interrupted by another task, the values of v2 and v9 will be the same.
I use eventset only to see if SetEvent() goes wrong. Is this test meaningless?
You are right about auto-reset option. I modified CreateEvent to autoreset. And now ALL IS OK!! THANKS!
Sergey Alexandrovich Kryukov 2-Oct-13 2:10am    
This test would make sense for research purpose but meaningless for functionality. For research, you can make sure, for example, that no other thread interfere with certain action during certain period of time, and based on that, infer some conclusion. In production, you don't know what exactly may happens, so your code should leave zero chance for any random failure. That's why threading code should be analyzed theoretically, not just tested.

Now, this is such a pleasure to help someone who can get help, analyze the problems and actually make things happen. You are very welcome.

Good luck, call again.
—SA

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900