LabWindows/CVI

cancel
Showing results for 
Search instead for 
Did you mean: 

Help needed with multi-threading

hi,

I am new to multi-threading and need some help. Currently, i am seeing some weird behaviour in my program and do not understand why. I also have some questions at the bottom.

i have an active x richtextbox.fp, easytab.fp, async timer.fp and msie.fp

// still in main thread
// a picture button also calls this function
void CVICALLBACK Execution (int menubar, int menuItem, void *callbackData, int panel)
{
// Do some stuff

CmtScheduleThreadPoolFunction (DEFAULT_THREAD_POOL_HANDLE, ExecutionThread, NULL, &ExeThreadID);
CmtWaitForThreadPoolFunctionCompletion (DEFAULT_THREAD_POOL_HANDLE, ExeThreadID, OPT_TP_PROCESS_EVENTS_WHILE_WAITING);
CmtReleaseThreadPoolFunctionID (DEFAULT_THREAD_POOL_HANDLE, ExeThreadID);

// Updates Stuff
}

int CVICALLBACK ExecutionThread (void *functionData)
{
// Creates Async Timer
TimerHandle = NewAsyncTimer (TimerInterval, 1, 1, ExecutionTimer, NULL);

// go to function
execution ()

return 0;
}

int CVICALLBACK ExecutionTimer (int reserved, int theTimerId, int event, void *callbackData, int eventData1,
int eventData2)
{
if (event == EVENT_TIMER_TICK)
{
if (TimerHandle == theTimerId)
{
TimerFlag = 1;
}
}
return 0;
}

void execution (void)
{
while StopFlag == 0
{
if TimerFlag == 0
//does some stuff
else
PostDeferredCallToThreadAndWait (ExeTimeUp, 0, CmtGetMainThreadID(), POST_CALL_WAIT_TIMEOUT_INFINITE);
}
}

void CVICALLBACK ExeTimeUp (void *callbackData)
{
Status = ConfirmPopup ("Timer", "Time is up!\n Would you like to continue?");
if (Status == 1)
{
TimerFlag = 0;
TimerHandle = NewAsyncTimer (TimerInterval, 1, 1, ExecutionTimer, NULL);
}

else
{
MessagePopup ("Program", "Program Terminated!");
TimerFlag = 0;
StopFlag = 1;
}
}

// a picture button also calls this function
void CVICALLBACK Stop (int menubar, int menuItem, void *callbackData, int panel)
{
StopFlag == 1
}


During execution, user is only allowed to press on the Stop button (calls stop callback).

Problem 1:the timer confirm popup panel appears much later after timer flag is set to high and it is not because of the while loop.

Problem 2: sometimes if user clicks on the stop button, the thread is terminated (Look from the variables window>>run>>thread) but the program is still waiting at CmtWaitForThreadPoolFunctionCompletion.

Question 1: can CmtWaitForThreadPoolFunctionCompletion actually receives the PostDeferredCallToThreadAndWait immediately?

Not sure if this is the correct way to write the program.

Thanks in advance, any help or advice would be much appreciated.

Cheers
AL
0 Kudos
Message 1 of 16
(5,372 Views)
Hi AL,
I think your approach is close, but I would point out one relatively import thing. You shouldn't allow two threads to write to the same variable; that's a multi-threading no-no. In your code, the thread that runs ExeTimeUp (your main thread) and the thread that runs ExecutionTimer (your async timer) can both write to your variable TimerFlag. And if you are really nit-picky, you may not want a second or third thread to even get a 'dirty read' of this value--meaning one thread gets a copy with one value and starts running logic while a second thread sees a different value and your two threads go separate ways in their logic, or step onto each other.

I would tend to disarm the async timer callback in the first line of the Stop callback also, and then follow with a discard timer--just to make sure the timer callback doesn't get a chance to accidentally fire after the shooting match is already over. You will need to look at the documentation of thread-safe variables. There is a link to a PDF file from the CVI help system. It kind of walks you through all of the CVI multithreading concepts, but you need to play with it to see it work in action.

Good luck,
Orlan
0 Kudos
Message 2 of 16
(5,343 Views)
Oh yeah,
If you don't want to wait for the thread function to complete, you can leave your scheduling logic open-ended (you just start the ball rolling) and complete the follow up logic that you have after the thread scheduling in the thread function's callback. I like function callbacks, but maybe some people don't.

Orlan
0 Kudos
Message 3 of 16
(5,340 Views)
You may find some information in the MultithreadingOverview.pdf file that you will find in C:\Program Files\National Instruments\CVI71\bin

Feel free to spend some time running all the examples in the
C:\Program Files\National Instruments\CVI71\samples\utility\Threading directory

If you can read this book

Finally, try to have a look on this page page

My final advises would be
- yes, you can use Windows SDK multithread API in CVI apps but don't spend your time doing it. It is a waste of time and debuging will not be possible easily
- if needed use Sleep function from the Windows SDK instead of the Delay fonction (coming with CVI)
Regards, Philippe proud to be using LabWindows since version 1.2
// --------------------------------------------------------------------------------------------
0 Kudos
Message 4 of 16
(5,335 Views)
Hi Cosmo and Zarma,

thanks for the reply and the useful information provided.

cosmo: i have a question...

In most of the examples, provided by Ni, they use a while loop running the threads..
while (!gExiting)
{
0 Kudos
Message 5 of 16
(5,305 Views)
Hi Cosmo and Zarma,

thanks for the reply and the useful information provided.

i have a question...

In most of the examples, provided by Ni, they use a while loop running the threads.
while (!gExiting)
{
// do some stuff
}

this gExiting variable is change by other threads.

i have tried to replicate this using the variable TimerFlag and StopFlag.

In my program, execution() is the one which has the while loop (variable StopFlag) with a nested If statement (Variable Timerflag).

Should i move this 2 variables to be a thread safe variable?

I'm not too sure if this is actually the cause of problem 1.

Can someone please reply to my question 1 as well in my first post?

Thanks once again.

Regards
AL
0 Kudos
Message 6 of 16
(5,305 Views)
oops sorry for the partial post number 5, i must have press tab and enter at the same time... is there no way to get rid of it?

Cheers
AL
0 Kudos
Message 7 of 16
(5,306 Views)
hi AL,

I recreated the sample code that you posted and dug into it again. In my test copy, the thread scheduling functions are executed by my main thread. In yours it may be different, but I did see the delay misbehavior that you spoke of.

I set a Beep() in the timer callback, so that I can hear when it fires--and it is firing on schedule. But I noticed two completely different behaviors with respect to ExeTimeUp(). When my mouse pointer is off the panel (whether I move it or not), ConfirmPopup() doesn't fire. When my mouse pointer is on the panel, ConfirmPopup() will only fire quickly if I move the mouse after the beep (just even 1 pixel).

I kept testing different things, but it almost looks like the main thread is stuck in CmtWaitForThreadPoolFunctionCompletion(). It's like the PostDeferredCallToThreadAndWait() is not 'powerful' enough to pull the main thread out of CmtWaitForThreadPoolFunctionCompletion(), even though the OPT_TP_PROCESS_EVENTS_WHILE_WAITING option is set. But, when a mouse movement on the panel occurs, it has no choice and must leave that function. Then, of course, it sees the deferred call from the ExecutionThread and then runs it. I think it shouldn't work this way, but it seems to.

As an aside, I went ahead and rewrote the sample code using thread-safe variables and a thread function callback. Check it out. It isn't succeptible to the WaitForThread...() 'personality'.

Orlan
Message 8 of 16
(5,282 Views)
This post might explain the affect you are seeing.
Bilal Durrani
NI
0 Kudos
Message 9 of 16
(5,273 Views)
Yep,
I wasn't watching that other thread, but that matches exactly what I was just describing. After a retrospective look at the function help for PostDeferred...AndWait():

'If the thread id you pass is different than the current thread's id, PostDeferredCallToThreadAndWait() calls PostDeferredCallToThread() and then sleeps until your callback finishes executing or until the timeout expires.'

In the original sample code, the PostDeferred...AndWait() is being called from a worker thread back to the main thread. Just like it says, this changes functionality back to PostDeferredCallToThread() and now you need the PostThreadMessage() that Luis suggested in the other thread. This 'pokes the main thread with a stick' to wake it up. That's also why the mouse movement over the panel worked, because it sent a mouse message to the main thread.

Thanx Bilal, I just went back and gave Luis some more stars....The new sample code that I wrote doesn't rely on either of those calls, so if nothing else it can be just another sample project to look at.

Orlan
Message 10 of 16
(5,262 Views)