Multithreading

<< Click to Display Table of Contents >>

Navigation:  Image Manager > CVB Technology >

Multithreading

 

The following section describes the use of multithreading in Common Vision Blox.

 

These notes are targeted primarily at users who have multiple image acquisition devices in a system, or who are working with the Coreco Imaging IC-Async.

Registry settings are described and should only be used in the above cases.

It is highly advisable not to make any changes to registry settings if only one frame grabber or no IC-Async is installed in the system.

 

We will be looking at the ping-pong method of acquisition in a separate thread.

It appears somewhat complicated on the surface and there are also two different methods, the difference is only slight but difficult to describe.

Readers who have already developed multithreading applications will recognize the difference easily.

The following figure shows the non-default method:

 

imageocx1

 

This case only applies when the driver that is used supports ping-pong and the PingPongEnabled property of the Image Control has been set to TRUE.

When the Grab property is set to TRUE for the first time, a separate thread is started.

This thread runs in parallel to the application thread and serves exclusively to acquire images with the aid of the ping-pong interface.

However, the images generally need to be processed in the application and the two threads must therefore be synchronized in some way.

This synchronization is done by means of events.

 

An event is a connection between occurrences in the Control and the application in which the Control is located.

The end points of this connection are called the event source and event sink.

When the event has been triggered, the Control branches to this function if a sink function has been specified in the application.

Basically, an event can therefore be regarded as a callback function.

 

Now we come to the difference between the two methods :

In the first method the ImageSnaped event is executed directly from the acquisition thread of the Control , and is not passed to the applications message queue for further processing.

For the application, this means that everything that is done in the event potentially involves unreliable thread handling.

A classic example of this is a list of threads which is processed in the ImageSnaped event.

At the same time the program provides buttons with which new threads can be inserted in the list or existing ones deleted from it.

If no synchronization takes place, users can delete a thread from the list while this element is being accessed in the event.

Inexperienced users fall into an unpleasant trap if they are not aware of this situation.

For this reason we have implemented a simple form of synchronization with the user interface in the Common Vision Display and Image Controls.

 

The event is triggered by the client's message queue.

This ensures that no user inputs are possible while the event is executing.

This is the second, non-default method.

 

Switching between the two modes is implemented by a flag in the registry.

Under HKEY_LOCAL_MACHINE\SOFTWARE\Common Vision Blox\Image Manager there is a DWORD value named GlobalAsyncACQ Enabled.

A value other than 0 disables synchronization via the message queue. A value of 0 (default) enables it.

The default value should not be changed for normal applications.

If, however, multiple image acquisition device instances and thus multiple Image Controls are in use, the value should be changed to ensure that the application handles threads reliably.

 

A simple test illustrates the difference.

Take two Image Controls and load two drivers. Each Control is assigned a driver instance.

A Sleep(1000) is called in the ImageSnaped event of one Control .

If the Grab property of both Controls is set to TRUE, the second display acquires new images at frame rate whereas the first display only acquires a new image every second.

This requires Global AsyncACQ Enabled to have been set to 1, the two displays therefore run in parallel.
If Global AsyncACQ Enabled has been set to 0, the two displays run at just one image per second because the slower thread delays the other one (there is only one message queue).

 

Experienced developers will have noticed a striking infringement of the Microsoft Windows Design Rules in the case of asynchronous acquisition.

According to Microsoft, the user interface (UI) is not allowed to be accessed from multiple threads at the same time.

This is understandable because the output device only has one logical pixel x, y which can only assume one state. Some kind of synchronization between the threads is therefore needed.

 

This puts Common Vision Blox in a tricky situation because users can extend the acquisition thread by means of the ImageSnaped event.

For instance, users can call the AddDisplayLabel method, which draws a label over the image as an overlay, in the ImageSnaped event.

In this case, changes are made to the UI from the thread.

Common Vision Blox could provide safeguards against all dangerous calls but this would lead to a drop in performance, therefore the Image and Display Controls open up their internal synchronization objects allowing users the opportunity to ensure that their calls handle threads reliably.

Everything that is under the direct control of Common Vision Blox (e.g. interactive zooming, scroll bars etc.) is safeguarded internally.

 

All external UI functionality has the potential for unreliable thread handling, it has to be made reliable by means of synchronization objects.

At this point we must stress that this tricky situation does not originate solely with Common Vision Blox UI calls but affects all outputs with Windows UI functions in all programs.

If, for example, MFC is used to display text in a text box from a second thread, the program will crash pitilessly.

Visual C++ users must draw upon SDK functions to enable UI outputs from a separate thread.

 

Two methods are available in the Controls for synchronization:

 

Lock () : ... locks all internal outputs of all instances of the Image or Display Control

Unlock () : ... unlocks the above

 

If labels are to be added to an image in the ImageSnaped event, the CVDisplay.AddLabel(...) call has to be inserted in a Lock-Unlock block.

Of course, there is only necessary if GlobalAsyncACQ Enabled has been set to a value other than zero which, in turn, only makes sense if multiple independent acquisition threads have to run (e.g. when multiple image acquisition devices are going to be used simultaneously).

 

The acquisition thread thus branches to the application using one of the two methods described above and remains there until the event function is exited.

The reason for this is that we want to evaluate images.

There is no point running a thread that constantly acquires new images which cannot be processed, thereby consuming valuable computation time.

In the figure above, the course of the acquisition thread is marked in red.

 

Attentive readers will have noticed a disadvantage of the implementation here.

The application is not told in any way whether all images were processed or how many images were not processed.

The application may need to acquire various images quickly one after another for processing later.

The solution to this lies not just in creating a memory area for the image but also in managing the images in a circular buffer of adjustable size.

If the circular buffer is big enough, the application described above can be implemented.

Such a procedure can be implemented with the functions that are currently available in Common Vision Blox (see Sequence tool for example).

 

Related Topics

 

GetGlobalAsyncACQEnabled and SetGlobalAsyncACQEnabled functions from Utiilites Dll

Lock and Unlock method of the Display Control