multithreadinglabwindowscvi

DiscardAsyncTimer returning before timer callback is complete


I'm trying to write a program in LabWindows/CVI 2017 using async timers but ran into a problem with the DiscardAsyncTimer() function. From the documentation for DiscardAsyncTimer():

A call to create or discard an asynchronous timer will not complete (will block) until all outstanding asynchronous callbacks return.

However, I ran into some memory problems where I was freeing memory used in my async timer thread after calling DiscardAsyncTimer(). I expected the memory to no longer be in use, but apparently this is not the case? I have an example program below that recreates my problem. When run, this program generates a "general protection fault" due to trying to access freed memory. However, if my understanding of the documentation, and the documentation itself, is correct, this should be impossible since DiscardAsyncTimer() is supposed to block until all callbacks return.

My questions:

  1. Am I understanding the documentation correctly?
  2. Am I doing something stupid in this example?
  3. How am I supposed to verify that my async timer threads have completed running before freeing the memory?

Example program:

#include <ansi_c.h>
#include <asynctmr.h>
#include <stdio.h>
#include <utility.h> 
#include <userint.h>


typedef struct {
    int* array;
} MyStruct;

int CVICALLBACK ShuffleValues (int reserved, int timerId, int event, void *callbackData, int eventData1, int eventData2)
{
    if (event == EVENT_TIMER_TICK) {
        printf("start\n");
        MyStruct* mystruct = callbackData;

        // Shuffle values
        for(int i = 0;i < 1000;i++) {
            mystruct->array[0] = mystruct->array[1];
            mystruct->array[1] = mystruct->array[2];
            Delay(0.01);
        }

        printf("finished\n");
    }

    return 0;
}

int main ()
{
    // Allocate memory
    MyStruct* mystruct = malloc(sizeof(MyStruct));
    mystruct->array = malloc(10 * sizeof(int));

    // Start Async Timer
    int timer = NewAsyncTimer(0.01, -1, 1, ShuffleValues, mystruct);

    // Wait a while to let the timer thread run a bit
    Delay(0.5);

    // Destroy Async Timer  
    printf("start destroying\n");
    int retval = DiscardAsyncTimer(timer);
    printf("finished destroying: %d\n", retval);

    // Free memory now that the timer thread is no longer running
    free(mystruct->array);
    free(mystruct);

    Delay(1);
    return 0;
}

I also asked this question on the LabWindows/CVI forum a week ago without any response: https://forums.ni.com/t5/LabWindows-CVI/DiscardAsyncTimer-returning-before-timer-callback-is-complete/td-p/3943460


Solution

  • I hadn't seen your question on the NI forum. The quick answer is that async timers run in a separate thread, so you need to take the usual precautions. When the error occur you can see that with [Windows][Threads] and jump from one thread to the other. Use a volatile variable for synchronisation, or better a semaphore.