04-16-2010 02:40 PM
I have to start this off by saying that I am not a very good programmer. I am building an instrument which requires some computer interface, and I've been learning how to program as I write the program, mostly working from documentation (which means that I've re-written half the program a bunch of times as I've learned new things like how to define data structures and whatnot).
My question is about multithreading - in my application, I use the GUI to write a set of instructions, then I press a "Start Button" which loads the instructions onto a board which interprets them and outputs some precisely-timed digital logic. Additionally, if specified, the "Start Button" starts a DAQmx task which takes a trigger from my board and acquires data. Since these scans can take a while, it's best for me to run them in a separate thread. I'm also trying to run an additional thread which periodically queries the board for its status - whether it is running, waiting for a trigger or stopped - and updates an LED control to reflect the status. The problem I'm having is that the function of programming the board and the function of checking the status has some overlap, which I imagine is why I am getting General Protection Faults. I've read about Thread Locks and Thread Safe Queues, but those seem to be mostly about passing data between threads. Ideally, I'd like to be able to make sure two threads do not call the same function at the same time - how would I implement this?
Additionally, I'm not sure if this is a problem of the two threads calling the same function at the same time (I don't know if this is a problem or not), or if the problem is with the fact that when I call these functions, they need to access the USB interface and maybe there are some kind of conflicts between them. I am really hitting a wall here because I think I don't have a strong understanding of how memory allocation and function stacks work.
Solved! Go to Solution.
04-16-2010 04:37 PM
Hi Paul, from your description it seems very likely that you are facing problems with contemporaneous access to the same resource from multiple threads, which could explain the GPF you are receiving.
Thread locks are a common way to handle such situations, as they can permit one thread to protect from another thread access to the shared resource.
The way locks are used is:
1. Create a lock before you need to use it (possibly at program start)
2. When a thread needs access to USB port to communicate with the instrument it must call CmtGetLock to lock access from other threads: if the lock is free, it is acquired by the threads; if it is already owned by another thread, the thread waits in CmtGetLock function until the lock is free
3. After a lock has finished using the shared resource, it must call CmtReleaseLock to permitt access to the resource from other threads
4. At program end, destroy the lock
If you don't want a thread to stay freezed within CmtGetLock there is a function in the library that whether the lock is free or not, so you can stay in a loop waiting for the lock to be free but with the thread still alive and able to continue its work (still without access to the shared resource, obviously).
It is crucial that acquired locks are always released, otherwise the other threads will be permanently excluded from accessing the shared resource: this consideration is particularly important when adding error handling to the threads, since you must be sure to release the acquired locks even in case of errors, when one common politics is to jump to an error handling lable inside the function and it is possible that a lock is kept acquired.
04-16-2010 06:05 PM
Thanks! I was thinking that that might be the right thing to do, but it wasn't entirely clear. This seems to have stopped the GPFs. Of course, once the GPFs were gone some other problems have arisen. There are no longer conflicts causing GPF, but it is consistently giving me errors reading from the board for some reason. I think I'll need to take some time to figure out where those errors are coming from.
One last question - will it ever "skip" execution of a command for some reason? My current problem is that occasionally this function I call will return something like 61013216 (it should be returning a number between 1 and 32. I'm wondering if the reason for this is that the execution was somehow skipped or it has pointed to the wrong bit of memory or something.
04-17-2010 01:33 AM
It is difficult to try guessing what's happening with only a brief description of the system... CVI does not skip instructions for whatever reason, I am more prone to think that a possible problems may arise in interaction with your board. Let me explain.
You were receiving GPFs due to conflicts in accessing a shared communication resource like a USB port: this means that in some occasion different tasks in your program are trying to communicate with the external board in the same moment. This makes me doubt wheteher the board is always ready to respond to every single command received or on the contrary may the board itself be missing some command, or even sending to a task the answer to another if the second command has been recevied while handling the first one. Wheter this is possible or not depends both on the external instrument and on the way your program is realized and it's not possible to guess from aside: I just wanted to point you to this possibility.
One possibility to debug this situation could be to stop one of the tasks and see if the answers received are always correct or not. If you cannot do it or if the status you are querying depends on the first task to be running, you could try adding some delay between the commands in order to be sure that the external board is ready to receive instructions. If you succeed in solving the situation this way you can progressively shorten the delays to achieve the best compromise between responsiveness and confidency in handling requests.
04-17-2010 03:02 PM