LabWindows/CVI

cancel
Showing results for 
Search instead for 
Did you mean: 

How to use Multithread in my program

Hello ,
 I meet a problem during my work, I need pause or stop the  program during it is running ,but I don't know how to do it ,I know nothing adout the Multithread,so I read the articles of  Forums,but it still can't afford my requirement.  I am new to multithreading so I'm hoping my question has an obvious answer. I am running a GUI, one of whose commands is "Test start". This command takes a long time to execute,in the Callback Function,there is another function to execute , so I want to be able to interrupt its execution any time.
Below is part of  my program:
 

int main (int argc, char *argv[])
{
 if (InitCVIRTE (0, argv, 0) == 0)
  return -1; /* out of memory */
 if ((panelHandle = LoadPanel (0, "singelUI.uir", PANEL)) < 0)
  return -1;
 DisplayPanel (panelHandle);
 RunUserInterface ();
 DiscardPanel (panelHandle);
 return 0;
}
int CVICALLBACK Test (int panel, int control, int event,
  void *callbackData, int eventData1, int eventData2)
{   int freq;
    int level;
 switch (event)
  {
  case EVENT_COMMIT:
  GetCtrlVal(panelHandle,PANEL_FREQUENCY,&freq);
  GetCtrlVal(panelHandle,PANEL_POWERSPAN,&level);
  SingleFreqSinglePowerSpan(level,freq);
   break;
  }
 return 0;
}
Single FreqSinglePoweSpan() is a  function who will spend lots of time to execute.What I need is i could interrupt its execution .For example :when i click Stop or Pause ,it should stop or pause  .What shoule i do ?
thanks
0 Kudos
Message 1 of 7
(4,226 Views)

Your problem is not necessarily solved by using multithreading: the simplest approach of all is to call periodically ProcessSystemEvents () into your long-lasting function: this way you can execute a button callback that raises a global flag to signals test function to stop. Someting like this:

int  stop;     // A global variable

int  TestFunction (void) {
   //...
   while (!stop) {

      // Your function code

      ProcessSystemEvents ();   // This permits execution of stopButtonCallback
   }
   return 0;
}

int StopButtonCallback (...) {
   if (event == EVENT_COMMIT) stop = 1;
   return 0;
}

 

Another approach can be to use a toggle button as a stop button and periodically test its value inside the testing routine. I'm not sure of it but it could permit you to avoid the ProcessSystemEvent (); surely you avoid the button callback and the use of a global variable. The routine could then be as follows:

int  TestFunction (void) {
   int   stop;   // A local variable

   //...
   while (1) {

      // Your function code

      GetCtrlVal (panelHandle, stopButton, &stop);
      if (stop) break;
   }
   SetCtrlVal (panelHandle, stopButton, 0);    // Reset stop button
   return 0;
}

 



Proud to use LW/CVI from 3.1 on.

My contributions to the Developer Community
________________________________________
If I have helped you, why not giving me a kudos?
0 Kudos
Message 2 of 7
(4,213 Views)

Hi Roberto,thank you for your reply.

I try it follow your example,but it doesn't work,

In my function ,there are lots of equipments under controllingand many loops , I changed my program like this :

int stop;

int main (int argc, char *argv[])
{
 if (InitCVIRTE (0, argv, 0) == 0)
  return -1; /* out of memory */
 if ((panelHandle = LoadPanel (0, "singelUI.uir", PANEL)) < 0)
  return -1;
 DisplayPanel (panelHandle);
 RunUserInterface ();
 DiscardPanel (panelHandle);
 return 0;
}

int CVICALLBACK Test (int panel, int control, int event,
  void *callbackData, int eventData1, int eventData2)
{   int freq;
    int level;
 switch (event)
  {
  case EVENT_COMMIT:
  GetCtrlVal(panelHandle,PANEL_FREQUENCY,&freq);
  GetCtrlVal(panelHandle,PANEL_POWERSPAN,&level);
  SingleFreqSinglePowerSpan(level,freq);
   break;
  }
 return 0;
}
void SingleFreqSinglePowerSpan(...)
{
  while(!stop)
  {
    //function code
   ProcessSystemEvents();
 
 }
 
}
int CVICALLBACK Stop(int panel, int control, int event,
  void *callbackData, int eventData1, int eventData2
{
  switch (event)
  {
    if(event==EVENT_COMMIT) stop=1;
   break;
  }
 return 0;
}
 
but it still doesn't work,  I can't  ciick any button during the function execution before the function end.
 
many thanks .
0 Kudos
Message 3 of 7
(4,203 Views)
Well, for this solution to work correctly you must place ProcessSystemEvents and test stop variable in every single loop of your function, non only in the outer loop (if any). Besides it, if functions are present tha intrinsically take log time to execute (as an example some syncronous acquisition functions that takes a few seconds to complete), you may observe severe latencies in responding to stop button and you may be missing the possibility to press the button. For this reason I prefere to use a toggle button that "memorizes" abort request until some loop executes it.
 
Second tip: your Stop callback needs to be simplified. You maitaned the switch (event) statement which is not necessary since there is the if (event...) row in it: cut away the swutch structure and leave only the if.
 
And last, your SingleFreqSinglePowerSpan function could be transformed into a deferred callback, so that in yout Test function you may use PostDeferredCall (SingleFreqSinglePowerSpan, ....); this way executint testing function after Test callback has terminated.
 
Hope this helps


Proud to use LW/CVI from 3.1 on.

My contributions to the Developer Community
________________________________________
If I have helped you, why not giving me a kudos?
0 Kudos
Message 4 of 7
(4,204 Views)

Another item that should be studied is how your software is structured: you may be stuck into I/O long operations that block the system su that even in multithreaded applications you cannot stop testing function or experience long "blind" intervals in reacting to user input. As an example, a syncronous DAQ acquisition than hangs the system until its completion, or a reading on serial or GPIB with a long timeout.

These functions can be rearranges to make them asyncronous. In traditional daq and pseudo-code it will look as follows:

DAQ_Rate ( ... );
SCAN_Setup ( ... );
SCAN_Start ( ... );
while (!stop && !iDAQstopped) {

   DAQ_Monitor ( ... , &iDAQstopped));
   ProcessSystemEvents ();
}
DAQ_Check( ... );
DAQ_Clear (1);

A reading function on RS232 instead of relying on com timeout can be rearranged as follows:

ComWrt ( ... ));
tini = Timer ();
while (Timer() - tini < 0.5 && !stop) {
  nch = GetInQLen (com);
  if (nch >= 2) {
   ComRd ( ... )));
   break;
  }
  ProcessSystemEvents ();
}

 



Proud to use LW/CVI from 3.1 on.

My contributions to the Developer Community
________________________________________
If I have helped you, why not giving me a kudos?
0 Kudos
Message 5 of 7
(4,195 Views)

Hi, Roberto,

How about if my test function is not is a loop? my test is GPIB operation and in a sequence, like

test1();

test2();

test3();

test4();

...

How can i break the test operation when i click the STOP button? do i need to put GetSystemEvent() everywhere?

Thanks,

Sam

 

0 Kudos
Message 6 of 7
(4,034 Views)

Sam, when interfacing with external hardware (via GPIB in your case) the characteristics of that hardware and communication mode have a great impact on the system. The instructions you are giving to external hardware may syncronous or not and that makes a great difference. In the first case you issue a command and your program is halted waiting for instrument response. In a structure like this you can have a separate thread for connecting to the instrument but you won't be able to process your Stop command issued in the main thread until instrument response has been received.

On the other hand, if you are using asyncronous communications you issue a command to the instrumens and enter a small loop waiting for its response: while the instrument is processing the command your application is free to perform other tasks. A structure like this can be interrupted easily with the methods described above.

So the question is how you are communicating to your hardware and I cannot answer this question for you. Smiley Wink

 

And to answer your final question, yes: you need to test if a stop command has been issued either in every single testx() function ar at least after completion of each of them.

Message Edited by Roberto Bozzolo on 07-26-2006 09:52 AM



Proud to use LW/CVI from 3.1 on.

My contributions to the Developer Community
________________________________________
If I have helped you, why not giving me a kudos?
0 Kudos
Message 7 of 7
(4,030 Views)