Supplemental Calls for Multithreaded NI-488.2 Applications
If you are writing a multithreaded NI-488.2 application and you plan to make all of your NI-488.2 calls from a single thread, you can safely continue to use the NI-488.2 global functions (Ibsta, Iberr, Ibcnt). The NI-488.2 global functions are defined on a per-process basis, so each process accesses its own private copy of the NI-488.2 global functions.
If you are writing a multithreaded NI-488.2 application and you plan to make NI-488.2 calls from more than a single thread, you cannot safely continue to use the NI-488.2 global functions without some form of synchronization (for example, a semaphore). To understand why this is true, take a look at the following example.
Assume that a process has two separate threads that make NI-488.2 calls, thread 1 and thread 2. Just as thread 1 is about to examine one of the NI-488.2 global functions, it gets preempted and thread 2 is allowed to run. Thread 2 proceeds to make several NI-488.2 calls that automatically update the NI-488.2 global functions. Later, when thread 1 is allowed to run, the NI-488.2 global that it is ready to examine is no longer in a known state and its value is no longer reliable.
This example illustrates a well-known multithreading problem. It is unsafe to access process-global functions from multiple threads of execution. You can avoid this problem in two ways:
Use synchronization to protect access to process-global functions.
Do not use process-global functions.
If you choose to implement the synchronization solution, you must ensure that code making NI-488.2 calls and examining the NI-488.2 global functions modified by an NI-488.2 call is protected by a synchronization primitive. For example, each thread might acquire a semaphore before making an NI-488.2 call and then release the semaphore after examining the NI-488.2 global functions modified by the call. For more information about the use of synchronization primitives, refer to the documentation on using Windows synchronization objects that came with your development tools.
If you choose not to use process-global functions, you can access per-thread copies of the NI-488.2 global functions using a special set of NI-488.2 calls. Whenever a thread makes an NI-488.2 call, the driver keeps a private copy of the NI-488.2 global functions for that thread. The driver keeps a separate private copy for each thread. The following code shows the set of calls you can use to access these per-thread NI-488.2 global functions.
unsigned long ThreadIbsta(); // return thread-specific Ibsta()
unsigned long ThreadIberr(); // return thread-specific Iberr()
unsigned long ThreadIbcnt(); // return thread-specific Ibcnt()
In your application, instead of accessing the per-process NI-488.2 global functions, substitute a call to get the corresponding per-thread NI-488.2 global. For example, the line of code
if (Ibsta() & ERR)
could be replaced by
if (ThreadIbsta() & ERR)
Note If you are using ibnotify in your application, the ibnotify callback is executed in a separate thread that is created by the NI-488.2 driver. Therefore, if your application makes NI-488.2 calls from the ibnotify callback function and makes NI-488.2 calls from other places, you must use the per-thread NI-488.2 global functions through ThreadIbsta , ThreadIberr , and ThreadIbcnt , instead of the per-process NI-488.2 global functions. |