03-04-2010 07:58 PM
Hi. Hope somebody can help me with this. I am trying to do simple mulitthreading with the NewAsyncTimer. The timer function draws the plot while the main thread gathers analog data from a DAQ. Since I am using a circular buffer array to gather the data while the other thread is drawing I use a struct with indexs and the array. The problem is that the stuct gets cleared when a CVI function is called. The code goes something like:
typedef struct{
int head;
int tail;
double graphArray[GRAPH_ARRAY_MAX];
}BUFFER;
BUFFER graphData; /*global struct*/
/*timer used to sample the DAQ at intervals*/
int CVICALLBACK tmr_CALLBACK (int panel, int control, int event,
void *callbackData, int eventData1, int eventData2) {
/*code*/
graphData.graphArray[graphData.head]=(voltage*gain)+offset;
graphData.head++;
if(graphData.head >GRAPH_ARRAY_MAX){
graphData.head=0;
}
SetCtrlAttribute(panelHandle, PANEL_gphDisplay, ATTR_ENABLE_ZOOM_AND_PAN, 1); /*PROBLEM OCCURS AFTER THIS OR SIMILAR CVI FUNCTION (like GetCtrlAttribute) IS EXECUTED. */
/*code*/
}
Wondering why the struct gets cleared when a CVI function is called. There are other global variables I use and they maintain their value but the struct doesn't.
03-05-2010 05:11 AM
Hi Kent,
Are you sure your buffer object is populated in the first place? Maybe it was already "clear" before your timer thread reads it.
You need to make sure you do not have race condition. Maybe a dataValid flag in the struct may help you with this.
Your DAQ thread sets the flag to true after filling in the buffer and your timer does not use the buffer if the flag is false.
Better than that, I would advise you to use the "Thread Safe Queue" as the data structure of choice for this application.
You can have your main thread read analog data and fill the queue with these samples, and the other one reading from the queue and empty it.
You can check the number of available samples in your plotting thread and read them at once if there are more than one.
This way you can also make sure you do not overwrite a previous sample. You should adjust the array size (according to your filling-emptying rates) for proper operation.
Hope this helps,
03-05-2010 10:13 AM
Thanks for the safe queue suggestion. I will try that.
I am sure the struct gets populated as I step through the code I watch it get filled out (the head index gets incremented). Then it executes the CVI functions and it gets cleared without executing the asycronous timer (the timer is set really slow ,.5sec, so I know that the data aquistion fuction should be ran atleast a couple of times before the timer executes to draw the screen).
03-05-2010 07:45 PM
Kent,
I wrote a little program to polish up my TSQ knowledge.
You can find it in the attachment.
Instead of a DAQ board I have an async timer generating random numbers at 40 Hz (later I increased it close to 1kHz without problems).
At each timer tick, the timer callback generates a random number, scales it to [-10,+10] interval and puts into the queue.
I installed a callback to get fired when the number of items in the queue reach 50. In that callback I plot all the samples available in the queue.
The timer intervals and queue size at the time of TSQ callback trigger are monitored as performance measures.
Hope you find it useful,