Aggelos Biboudis
Aggelos Biboudis

Reputation: 1195

What synchronization scheme should I choose to avoid deadlock on a realtime, C++/MFC application?

I would like to ask you a question regarding which concurrency facility (CMutex, CSemaphore, CEvent) should I choose, to make a C++/MFC, application multi-threaded.

It is a real time, machine vision application, that is required now to execute concurrently and it needs refactoring, from it's previous single-threaded status.

A single iteration of my workflow is the following. I have 2 producers A,B (MFC Workers) that need to fill two separate data structures (1 each). A third thread, a consumer (MFC Worker as well) is blocked, until both data become available from A and B. Then, producers A and B must block (each, upon their data completion), C must wake up, perform a calculation, unblock A and B to continue and become blocked again, waiting for the next segments.

  1. I must not use queues (Actor-like) - the blocking is a requirement :(
  2. I tried CEvent and it works. AutoResetEvents for A,B to unblock a CMultiLock call on C and then a ManualResetEvent->Set() from C, to unblock A and B waiting on the latter event. My concern is when to reset this event (in case e.g. A miss the whole Set and then Reset.)
  3. Do semaphores with plurality of 2 may stand for a better solution?

Best regards.

Upvotes: 2

Views: 336

Answers (4)

zar
zar

Reputation: 12237

You can simply use CEvent objects and than WaitForMultipleObjects() which allows you to wait on both objects via the third parameter 'bWaitAll'.

http://msdn.microsoft.com/en-us/library/windows/desktop/ms687025%28v=vs.85%29.aspx

Upvotes: 0

ravenspoint
ravenspoint

Reputation: 20576

I propose a signalling system, using a counter protected by a mutex. This keeps all the synchronization work confined to one small class that does notheing else.

A starts
A writes A-Data
A signals
A stops

B starts
B writes B-Data
B signals 
B stops

C starts
C reads A-Data and B-Data
C starts A, B
C stops


*Signal Class*

Mutex protected counter attribute

Receives signal for A, increment counter
Receives signal for B, increment counter
IF counter equals 2,  clear counter and start C

Upvotes: 0

Anthony Williams
Anthony Williams

Reputation: 68631

C must wait for two things to happen, so the most logical thing is that it waits for two auto-reset CEvent objects: one set by A and one by B.

When C is done, A and B must each then wait for a notification. Since there are two threads, and both must wake up, the natural thing is to use another pair of auto-reset CEvent objects, one for each of A and B. C can then set both when it is done.

A semaphore with a count of 2 would work for waking C --- C waits twice, and each of A and B notify --- but this means that C must wake up after the first notification in order to wait for the second, which is less than ideal.

Using a semaphore with a count of 2 for waking A and B afterwards has the potential for stolen wake-ups and confusion. C signals the semaphore twice. A wakes and takes a signal, does its processing and notifies C, and then waits on the semaphore again. Since B hasn't yet woken up, the semaphore is still available, so A takes it again. Meanwhile B is not stuck, since it won't get another signal, and C is stuck, since it will wait for the next value from B.

An alternative is to use the Windows Condition Variable API rather than events, but there doesn't seem to be an MFC wrapper for that. See http://msdn.microsoft.com/en-us/library/ms682052%28VS.85%29.aspx

Upvotes: 2

bdonlan
bdonlan

Reputation: 231313

I would go for a slight modification of your option 2 - use a CMultiLock on two events to block C; then use another pair of events to block A and B. C would set two auto-reset events to wake up each of A and B. Then you no longer have the race for the reset.

Upvotes: 2

Related Questions