Now, I have 2 buttons in a dialog box.
Pressing 'start' will activate the thread.
Pressing 'stop' has to terminate the thread.
I'm using an event (m_Finished) to indicate that the action is started. When the thread returns, I set the event, so I know the action is done.
Pressing the 'close' button, the application must quit, BUT the thread must be finished first. I'm using the 'm_Finished' event to see is the action is done. If it's still busy, I want the thread to be terminated before closing, so the OnClose() function has to wait until the thread is terminated).
Using the sequence 'start' -> 'stop' -> 'close' works.
Using the sequence 'start' -> 'close' should also be working, but it doesn't !
Apparently, the system gets stuck in the PeekMessage()-loop for the OnClose(), so the 'm_Finished' event is never set.
What's the cause of this behaviour ?
Andreas Masur
March 18th, 2004, 01:11 PM
[Moved thread]
cvogt61457
March 18th, 2004, 01:20 PM
Why do you need the message loop in the thread?
jvr2
March 18th, 2004, 03:19 PM
Maybe the PeekMessage() isn't necessary in the thread, I will try to remove it.
But I suppose that isn't the cause of my problem, since the program passes the thread without any problem, and it hangs somewhere else.
jvr2
March 19th, 2004, 04:31 AM
No, removing the PeekMessage() in the thread doesn't make a difference.
The program still gets stuck on the PeekMessage() in the OnClose() function.
For some reason, I believe WaitForSingleObject() in the OnClose() function is blocking the whole thing : it is waiting until the m_Finished event gets in the signaled state. That's exactly what I want, BUT ... for some reason, the WaitForSingleObject() in the OnBnClickedStart() function is blocked until the wait function in the OnClose() is done. And that isn't possible since that function is waiting on the m_Finished event :confused:
So ... I would like the WaitForSingleObject() in the OnClose() function to block the processing of that function until the m_Finished event is set, but in the meanwhile, the other processing must continue (e.g. setting the m_Finished event in OnBnClickedStart)
Any idea's ?
cvogt61457
March 19th, 2004, 10:05 AM
Here's a project that does what you want.
Note: Since you are using the CWinThread with default options,
there is a variable CWinThread::m_bAutoDelete that is by default
set to true. This means that the CWinThread object will
autodelete itself when the thread exits. You won't get the
WAIT_OBJECT_0. Instead you get WAIT_FAILED - the thread
handle no longer exists.
I've put in code so that you can try it both ways. Look at the
AfxCreateThread location and at the WaitForThreadExit().
When autodelete==true, you don't have to delete the CWinThread
object. The variable m_TheThread is reusable.
When autodelete==false, you do have to delete the
CWinThead object. After you delete the CWinThread object, you
can reuse m_TheThread.
I've got it setup so that you can start/stop/restart the thread
repeatedly.
cvogt61457
March 19th, 2004, 11:19 AM
When I think about it, be sure to set m_bAutoDelte = false.
This will keep the CWinThread object available for use after the
thread has exited.
Since you're wanting to wait for the thread exit, the CWinThread
object must be there for you to query. If the object is auto-deleted
then you don't know that the CWinThread pointer is pointing to
when you try to use the WaitForSingleObject() when you wait
for the thread exit.
The code that is currently active in the sample sets m_bAutoDelete
to false.
Because of this, you must delete the CWinThread object
yourself when you are finished with it.
jvr2
March 19th, 2004, 11:22 AM
Thank you very much for the effort !!!!!
Indeed, it seems to work that way.
Now, I'm only a few steps away from a structure that I can use in my program.
In the program you have written, you start the thread in the 'start' function, and the thread is deleted after pressing 'stop' or 'close'.
If you press the 'start'-button again before the thread is killed, the 'start' command is ignored by quiting the function immediatelly.
I guess the easiest way to illustrate what I wanna do, is by using your existing code ...
I made a few changes to the code :
1) I extended the 'ThreadData' with an integer member : 'factor'.
2) I added the following lines to the TestProc()-thread, so it can end processing itself when done.
3) I moved the code from the start-button to a function --> MyFunction(int factor)
4) I call MyFunction() from the 'start' routine
void CThreadTestDlg::OnStart()
{
MyFunction(0);
}
Apart of the fact that the thread can end when the processing is done (no stop event needed), the functionality remains the same.
And it still works ...
But now I would like to do multiple calls to the function :
MyFunction(10) must be executed after MyFunction(0) completed,
MyFunction(20) must be executed after MyFunction(10) completed, ..., but if the 'm_TerminateAsked' event is signaled before the last thread was finished, the remaining calls must be ignored.
eg.
----
Suppose I press 'start', MyFunction(0) must be executed.
If MyFunction(0) is done, MyFunction(10) must be started.
During the execution of that function, the 'stop'-button is pressed.
The thread must be interrupted, and the remaining calls MyFunction(20), MyFunction(30) and MyFunction(40) must be ignored.
Do you think that's easy to achieve, or is that rather complicated ?
Again, thanks for the effort.
cvogt61457
March 19th, 2004, 11:34 AM
What does MyFunction() actually do?
What you are wanting (I think) is to schedule multiple threads
according to the 'factor' that is given. Lower values of 'factor'
give the thread the higher priority.
Will each thread run the same activity?
Or will each thread (determined by 'factor') do something different?
This is vastly more complicated to running a single thread.
Not impossible.
You could use an std::array to keep track of all the threads that
have been started.
All you need to do is figure out the scheduling rules and get them
programmed in.
Note: In the Windows GUI, you don't want to do anything that
will take more than 1/10th of a second. This is the why many
programs need threads or message pumps.
When you call your MyFunction(N), does it setup the thread and
return immediately? Or does it wait?
Wait is not good.
jvr2
March 19th, 2004, 12:33 PM
No no, the factor has nothing to do with the priority !
I only needed a construction that made it possible that the thread could be completed without the user pressing one of the buttons.
The 'factor' is just an example, I wanted to make it clear that a successive call of the function must be possible. I wanted to use the code that you have written : by adding a (different) factor to each call of the thread, you should be able to see in which 'call' you are.
If the value that is displayed in the dialog box (thread counter) changes with steps of 1 (like it was before), MyFunction(0) is running.
Thread Counter 0 -> 1 -> 2 -> 3 -> ....
If the value that is displayed in the dialog box (thread counter) changes with steps of 11 (10+1) , MyFunction(10) is running.
Thread Counter 0 -> 11 -> 22 -> 33 -> ....
Actually, I wanna create an application that will write/read characters to/from the serial port.
Each write/read operation must be executed by a call to a thread because I wanna be able to interrupt the action by pressing a 'stop'-button.
So ... you could imagine that I wanna replace the MyFunction() routine with something like this :
void CThreadTestDlg::Send_Command(CString strCommand)
{
// here, I will have to start a thread that will handle the writing
}
The TestProc()-thread will be replaced with code to read/write characters from/to the serial port.
It is possible that multiple commands are sent immediately after each other. But only 1 command at a time may be executed. If I press the 'stop' button, the execution of the active thread must be finished, and the remaining commands that are waiting to be processed must be ignored.
cvogt61457
March 19th, 2004, 03:47 PM
I don't understand your app.
Instead of queuing the threads, I'd queue the commands and
send them in the order desired.
The send/receive thread(s) will be running on their own. When
a new command goes into the send queue, it will be sent. If there
is already a command in the process of being sent, then the new
command will go into the queue. When a command has completed
sending, then if there are any commands in the queue, then next
command will start sending.
std::vector would make this easy. Another STL container might be
better, I'm not that familiar with them yet.
Put something together and try it.
jvr2
March 20th, 2004, 06:09 AM
I'll try it.
Problem is : I already tried several constructions, but I always ended up with the system hanging ...
Indeed, it's a good idea to put the commands into a queue if the system is already busy.
But I suppose in that case I will need a loop that continuously will be checking if there are any command waiting to be send.
I will need to use some code like this :
bool bChecking = true;
while (bChecking==true)
{
GetExitCodeThread(hThread, &dwStatus);
if (dwStatus == STILL_ACTIVE)
{
// do nothing
}
else
{
// check if another command is waiting
// if so, start new thread
}
}
That loop will be using some system resources, and most of the time, that wouldn't be necessary because multiple commands will seldom occur (normally, it even isn't suppose to happen, but the program has to be prepared on all occations).
But maybe it isn't a bad idea. I can put the code above (checking if another command is waiting) in a separate thread, and I can start that thread after I push the 'start'-button. When the 'stop'-button is pressed, or if an external device (that is connected to the serial port) gives the instruction that is has finished with the commanded action, the thread can be terminated. Only problem that I see is the wait function in that thread. I don't want the 'checking' thread to block the other threads, or the processing of my progam.
I suppose I can use an 'autodelete' threads ?
Note :
--------
I'm writing an application to control a motor. That motor is connected to the PC through a serial port connection. So, at first I have to open the serial port connection. After that's done, I can start sending some characters to the motor (driver). Simplified, I must be able to write "P500S40" to the motor [using WriteFile() to serial connection], and then the motor will know that he has to move to position '500' with speed '40'. For that, I will use a 'command' thread. After the command is given, the motor starts to move, and the motor will continuously pass it's current position to the PC. For that, I will need a ReadFile-routine in the 'command' thread. When the motor is done, it passes the '0x80' to the serial connection, so the thread know the execution of the command is done, and that it can be terminated. After the thread has terminated, a new thread with a new command can be started. You see, it's sequential action, only 1 command at a time can be executed. And of course I must be able to terminated the execution of the 'command' thread by using a kind of 'stop'-button. Suppose a command is sent to the motor, but for some reason the serial connection is broken, then the connection will never get an 'ending character', and the application would hang (clearly, that must be avoided !).
I think it isn't so hard to write an application that will provide such functionality, but I'm not experienced in writing applications that use threads, nor in applications that use a serial communication. I guess that explains my problems ...
codeguru.com
Copyright WebMediaBrands Inc., All Rights Reserved.