Thread resource sharing
I'm struggling with multi-threaded programming...
I have an application that talks to an external device via a CAN to USB module. I've got the application talking on the CAN bus just fine, but there is a requirement for the application to transmit a "heartbeat" message every second.
This sounds like a perfect time to use threads, so I created a thread that wakes up every second and sends the heartbeat. The problem I'm having is sharing the CAN bus interface. The heartbeat must only be sent when the bus is idle. How do I share the resource?
Here is pseudo code showing what I have so far:
TMainThread
{
Init:
CanBusApi =new TCanBusApi;
MutexMain =CreateMutex( "CanBusApiMutexName" );
HeartbeatThread =new THeartbeatThread( CanBusApi );
Execution:
WaitForSingleObject( MutexMain );
CanBusApi->DoSomething();
ReleaseMutex( MutexMain );
}
THeartbeatThread( CanBusApi )
{
Init:
MutexHeart =CreateMutex( "CanBusApiMutexName" );
Execution:
Sleep( 1000 );
WaitForSingleObject( MutexHeart );
CanBusApi->DoHeartBeat();
ReleaseMutex( MutexHeart );
}
The problem I'm seeing is that when DoHeartBeat is called, it causes the main thread to block while waiting for MutexMain as expected, but DoHeartBeat also stops. DoHeartBeat doesn't complete until after WaitForSingleObject(MutexMain) ti开发者_运维知识库mes out in failure.
Does DoHeartBeat execute in the context of the MainThread or HeartBeatThread? It seems to be executing in MainThread.
What am I doing wrong? Is there a better way?
Thanks, David
I suspect that the CAN bus API is single-threaded under the covers. It may be marshaling your DoHeartBeat() request from your second thread back to the main thread. In that case, there would be no way for it to succeed since your main thread is blocked. You can fix this in basically two ways: (1) send a message to the main thread, telling it to do the heart beat, rather than doing it on the second thread; or (2) use a timer on the main thread for your heart beat instead of a second thread. (I do think that multithreading is overkill for this particular problem.)
First, re-read the specs about the heartbeat. Does it say that an actual heartbeat message must be received every second, or is it necessary that some message be received every second, and that a heartbeat should be used if no other messages are in flight? The presence of data on the channel is de-facto evidence that the communications channel is alive, so no specific heartbeat message should be required.
If an actual heartbeat message is required, and it's required every second, in the above code there should be only one mutex and both threads need to share it. The code as written creates two separate mutexes, so neither will actually block. You'll end up with a collision on the channel and Bad Things Will Happen in CanBusApi. Make MainMutex visible a global/class variable and have both threads reference it.
精彩评论