Messaging and Synchronization


In the last section, you learned about the queued message handler, which allows you to enqueue string message elements onto an array of string messages. This is a very powerful tool for application programming. But, LabVIEW also has some built-in tools for messaging and synchronization that allow you to implement some even more powerful applications. The Data Communication>>Synchronization palette (shown in Figure 13.80) contains the building blocks for complex, parallel, application logic, where dataflow becomes a little more fuzzy. These are the Queue, Notifier, Semaphore, Rendezvous, Occurrence, and First Call? VIs and functions.

Figure 13.80. Synchronization palette


Queues

Queues are one of the most commonly used messaging constructs. As we learned in the last section, where we discussed the queued message handler, a queue is an ordered set of elementsnamely, an array. To enqueue is to add an element to the queue, and to dequeue is to remove an element from the queue. The Queue Operations palette (shown in Figure 13.81) contains all the functions for operating on queues.

Figure 13.81. Queue Operations palette


The queue can be thought of as an array, which is operated on by referencemeaning, when you pass a queue around the block diagram of your VI using a wire, it is not the data of the queue that flows through the wire, but a reference to it. You cannot access the queue's array directly; you can only access the queue data through the various queue functions. To make the analogy easier to understand, see Figure 13.82 for a side-by-side comparison showing the analogous queue and array operations. You will learn more about the queue functions next. After learning about each of the queue functions, come back to this figure and study it to solidify this analogy.

Figure 13.82. Queues are simply arrays operated on by reference.


When you fork a queue reference wire, the queue is not copied. Rather, the reference is copied and both copies of the reference refer to the same queue. Many locations in your code can have a reference to the same queue; this is how they are able to share the queue and use it to communicate with each other.


Creating and Destroying Queues

In order to use queues, you will need to first create a queue. The Obtain Queue function (shown in Figure 13.83) creates a queue, or returns a reference to an existing (named) queue.

Figure 13.83. Obtain Queue


Obtain Queue (Data Communication>>Synchronization>>Queue Operations palette) returns a reference to a queue. You must specify the element data type, which is a polymorphic input that accepts any LabVIEW data type. This will define the data type used by the other queue functions when operating on the resulting queue. Use named queues to pass data between two sections of a block diagram or between two VIs. If you do not wire name, the function creates a new, unnamed queue reference. If you wire name, the function searches for an existing queue with the same name and returns a new reference to the existing queue. If a queue with the same name does not already exist and create if not found? is TRUE, the function creates a new, named queue reference.

Release Queue (Data Communication>>Synchronization>>Queue Operations palette) releases a reference to a queue (see Figure 13.84). If you are releasing a reference to a named queue (one that was given a name when created using the Obtain Queue function), in order to destroy the named queue, call the Release Queue function a number of times equal to the number of times you obtained a reference to the queue or stop all VIs using the queue reference.

Figure 13.84. Release Queue


If force destroy? is TRUE, this function releases all references to the queue and destroys the queue.

Enqueuing and Dequeuing Elements

Enqueue Element (Data Communication>> Synchronization>>Queue Operations palette) adds an element to the back of a queue (see Figure 13.85). If the queue is full, the function waits timeout in ms before timing out. If space becomes available in the queue during the wait, the function inserts the element and timed out? is FALSE. If queue becomes invalid (for example, the queue reference is released), the function stops waiting and returns error code 1122. Use the Obtain Queue function to set the maximum size of the queue.

Figure 13.85. Enqueue Element


Enqueue Element at Opposite End (Data Communication>>Synchronization>> Queue Operations palette) adds an element to the front of a queue (see Figure 13.86). This function is similar to the Enqueue Element function. If the queue is full, the function waits timeout in ms before continuing. If queue becomes invalid (for example, the queue reference is released), the function stops waiting and returns error code 1122.

Figure 13.86. Enqueue Element at Opposite End


Dequeue Element (Data Communication>> Synchronization>>Queue Operations palette) removes an element from the front of a queue and returns the element (see Figure 13.87). If the queue is empty, the function waits timeout in ms before timing out. If an element becomes available in the queue during the wait, the function removes and returns the element and timed out? is FALSE. If queue becomes invalid (for example, the queue reference is released), the function stops waiting and returns error code 1122.

Figure 13.87. Dequeue Element


Flush Queue (Data Communication>> Synchronization>>Queue Operations palette) removes all elements from a queue and returns the elements as an array (see Figure 13.88). This function does not release the queue reference. Use the Release Queue function to release the reference.

Figure 13.88. Flush Queue


Obtaining Queue Status Information

Get Queue Status (Data Communication>>Synchronization>>Queue Operations palette) returns information about the current state of a queue, such as the number of elements currently in the queue (see Figure 13.89). You also can use this function to verify that queue is a valid queue refnum. If queue is not a valid queue refnum, the function returns error code 1.

Figure 13.89. Get Queue Status


Preview Queue Element (Data Communication>>Synchronization>>Queue Operations palette) returns the element at the front of the queue without removing the element from the queue (see Figure 13.90). Use the Dequeue Element function to return the element at the front of the queue and remove it from the queue. If the queue is empty, the function waits timeout in ms before timing out. If an element becomes available in the queue during the wait, the function returns the element and timed out? is FALSE. If queue becomes invalid (for example, the queue reference is released), the function stops waiting and returns error code 1122.

Figure 13.90. Preview Queue Element


Activity 13-10: Building a Queued Message Handler Using Queues

In this activity you modify the Queued Message Handler template to use queues instead of an array of strings.

1.

Create a new queued message handler VI, from the template located in the File>>New . . . dialog. From the VI>>From Template>>Frameworks>> Design Patterns node, select Queued Message Handler.

2.

Convert the new queued message handler VI, so that it uses a queue, instead of an array of strings, as shown in Figure 13.91.

Figure 13.91. Block diagram of the VI you will create during this activity


If you do not wire to the timeout input of Dequeue Element (or if you wire a value of 1 into it), it will wait forever and never timeout. If you choose to wait forever, you must ensure that you are able to enqueue a message telling the While Loop to exit, or you can release/destroy the queue (which will cause the Dequeue Element function to stop waiting and return an error).

Note that we have removed the Wait (ms) function from the "No Event" case and have wired a 125 ms timeout to the Dequeue Element function. Because the Dequeue Element will wait 125 ms and then time out (if no elements are in the queue), we no longer need a wait timer inside of the "No Event" case.

3.

Save the VI as Queued Message Handler (using queues).vi.

Queue Examples, Templates, and Hints

For more examples showing how to use queues, look inside examples\general\queue.llb, found beneath your LabVIEW installation. There are also some very good templates that you can use to build your own VIs. Select the File>>New . . . from the menu to launch the New dialog. In the VI>>From Template>>Frameworks>> Design Patterns>> tree node, you will see the following options:

  • Producer/Consumer Design Pattern (Events)

  • Producer/Consumer Design Pattern (Data)

  • Master/Slave Design Pattern

Each of these templates uses queues to implement a very power framework design pattern.

And, here are some final hints for using queues:

  • You should generally only dequeue (read) elements from your queue in one location, called a consumer. It is, however, OK (and generally useful) to enqueue (write) elements to your queue in multiple locations, called producers. If you feel that you need multiple consumers, you should create a separate queue for each consumer.

  • You can obtain a reference to a named queue in multiple locations in your application. Just wire the queue name into the name input of the Obtain Queue function. Don't forget to wire the create if not found input when creating the named queue for the first time, or you will get an error.

  • Make sure to call Release Queue for each time you call Obtain Queue. This will help you avoid a memory hog application, which does not clean up after itself. If you are certain that a queue is no longer needed, you can pass a value of TRUE to the force destroy? argument of Release Queuethis will ensure that the queue is destroyed.

  • Make your queue element data type a type definition, as described earlier in the section, "Type Definitions." This will allow you to easily change your queue element data type at a later point in time.

  • Make your queue reference a type definition, as described in the "Type Definitions" section.

  • Consider making your queue element a cluster having two elements: the first element a string called command and the second element a variant called data. This will allow you to pass messages having both commands and arguments (data).

Notifiers

Notifiers are probably the second most commonly used messaging construct (with queues being the most commonly used). The Notifier Operations palette (shown in Figure 13.92) contains all of the functions for operating on notifiers. Just like a queue, a notifier has an element data type that you can define, but it can have only one element (unlike a queue, which has an array of elements). Notifiers are very useful in situations where you only need to have the latest message, and not all the messages. The notifier is most useful for broadcasting information to multiple locations, or consumers. A notifier usually has a single source, or producer, but it can (in some instances) be useful to have multiple producers.

Figure 13.92. Notifier Operations palette


Creating and Destroying Notifiers

Obtain Notifier (Data Communication>>Synchronization>>Notifier Operations palette) returns a reference to a notifier (see Figure 13.93). You must specify the element data type, which is a polymorphic input that accepts any LabVIEW data type. This will define the data type used by the other notifier functions when operating on the resulting notifier.

Figure 13.93. Obtain Notifier


Use named notifiers to pass data between two sections of a block diagram or between two VIs. If you do not wire name, the function creates a new, unnamed notifier reference. If you wire name, the function first searches for an existing notifier with the same name and returns a new reference to the existing notifier. If a notifier with the same name does not already exist and create if not found? is TRUE, the function creates a new, named notifier reference.

Release Notifier (Data Communication>>Synchronization>>Notifier Operations palette) releases a reference to a notifier (see Figure 13.94). You can use the Obtain Notifier function to obtain a reference to the same notifier with the same name multiple times. To destroy a notifier, call the Release Notifier function a number of times equal to the number of times you obtained a reference to the notifier or stop all VIs using the notifier reference.

Figure 13.94. Release Notifier


If force destroy? is TRUE, this function releases all references to the notifier and destroys the notifier.

Sending and Waiting on Notification

Send Notification (Data Communication>> Synchronization>>Notifier Operations palette) sends a message to all functions waiting on a notifier (see Figure 13.95). All Wait on Notification and Wait on Notification from Multiple functions currently waiting on the notifier stop waiting and continue to execute.

Figure 13.95. Send Notification


Cancel Notification (Data Communication>>Synchronization>>Notifier Operations palette) erases any message currently in a notifier and returns the canceled message (see Figure 13.96). If any Wait on Notification or Wait on Notification from Multiple functions received the message before the call to this function, those functions continue to execute.

Figure 13.96. Cancel Notification


This function does not recall or reset any wait functions. After you cancel a notification, any subsequent wait functions wait until the notifier receives another message. Canceling a notification before the notifier has a message does not result in an error.

Wait on Notification (Data Communication>>Synchronization>>Notifier Operations palette) waits until a notifier receives a message (see Figure 13.97). When the notifier receives a message, this function continues to execute. Use the Send Notification function to send the message. If a notifier reference becomes invalid (for example, when another function closes it), the function stops waiting and returns error code 1122. If the notifier does not contain a message, this function waits until the notifier receives a message.

Figure 13.97. Wait on Notification


Each unique instance of this function remembers the time stamp of the last message it read.

If ignore previous is FALSE, each instance of the Wait on Notification function waits if the message in the notifier has a time stamp for the same time that the instance of the function last executed. If the message is new, then the function returns the message.

When ignore previous is TRUE, the Wait on Notification function always waits for a new message, even if the message currently in the notifier is one it has never seen before.

This function does not remove the message from the notifier. Although a specific instance of the function returns a message only once, other instances of the function or to the Wait on Notification from Multiple function repeat the message until you call the Send Notification function with a new message.

Wait on Notification from Multiple (Data Communication>>Synchronization>> Notifier Operations palette) waits until at least one of the specified notifiers receives a message (see Figure 13.98). When one of the notifiers receives a message, this function continues to execute. Use the Send Notification function to send the message. If a notifier reference becomes invalid, such as when another function closes it, this function stops waiting and returns error code 1122. If the notifier does not contain a message, this function waits until the notifier receives a message.

Figure 13.98. Wait on Notification from Multiple


This function is similar to the Wait on Notification function.

Each unique instance of this function remembers the time stamp of the last message it read. If this function receives only one message, the function stops remembering which message the time stamp refers to, and the only item filled in the notifiers array is the first element.

If ignore previous is FALSE, each instance of the Wait on Notification from Multiple function determines if one or more notifier has a message newer than the time stamp most recently received by this function. If one or more of the notifiers has new messages, all messages are returned.

When ignore previous is TRUE, this function always waits for a new message, even if the message currently in the notifier is one it has never seen before.

This function does not remove the message from the notifier. Although a specific instance of the function returns a message only once, other instances of the function or to the Wait on Notification function repeat the message until you call the Send Notification function with a new message.

Obtaining Notifier Status Information

Get Notifier Status (Data Communication>>Synchronization>>Notifier Operations palette) returns information about the current state of a notifier, such as the last uncancelled notification sent to the notifier (see Figure 13.99).

Figure 13.99. Get Notifier Status


Notifier Examples and Hints

For more examples showing how to use notifiers, look inside examples\general\notifier.llb, found beneath your LabVIEW installation.

And, here are some final hints for using notifiers:

  • You should generally use notifiers only if you are not concerned about missing a notificationyou only care about the latest messages. If you don't want to miss any message, use a queue instead of a notifier.

  • Notification can be sent (produced) and received (consumed) in multiple locations. It is generally used to broadcast information, such as status. For example, it is very useful for updating indicators on a user interface, where you only care to update the indicators with the latest data.

  • You can obtain a reference to a named notifier in multiple locations in your application. Just wire the notifier name into the name input of the Obtain Notifier function. Don't forget to wire the create if not found input when creating the named notifier for the first time, or you will get an error.

  • Make sure to call Release Notifier for each time you call Obtain Notifier. This will help you avoid a memory hog application, which does not clean up after itself. If you are certain that a notifier is no longer needed, you can pass a value of TRUE to the force destroy? argument of Release Notifierthis will ensure that the notifier is destroyed.

  • Make your notifier element data type a type definition, as described in the earlier section, "Type Definitions." This will allow you to easily change your notifier element data type at a later point in time.

  • Make your notifier reference a type definition, as described in an earlier section.

  • Consider making your notifier element a cluster having two elements: the first element a string called source and the second element a variant called data. This will allow you to send notification messages containing a lot of useful information.

Semaphores: Locking and Unlocking Shared Resources

The VIs found on the Semaphore palette (shown in Figure 13.100) allow you to lock and unlock a shared resource. A shared resource might be a communication pipeline (such as a TCP connection), an external instrument (such as bench-top GPIB instrument), data (such as a global variables), or anything that can only be operated on by one (or a fixed number of) process(es) at a time.

Figure 13.100. Semaphore palette


Unlike a queue or a notifier, a semaphore has no data. Rather, it is used purely for synchronizationto provide exclusive sequential access (via a lock/unlock mechanism) to some shared resource. (A semaphore is sometimes referred to as mutex, or mutual exclusion.) Figure 13.101 shows a typical use case where a semaphore is used to enforce sequential (one at a time) access to a shared resource. The secret to how this works is that once Acquire Semaphore (the lock function) has been called in one location, if it is called again in any other locations, the subsequent calls will wait until Release Semaphore (the unlock function) is called and it is "their turn" to execute. (They will execute in the order that they started waiting.)

Figure 13.101. Semaphore Example.vi showing how to lock a shared resource


You will learn more about the semaphore functions next.

Creating and Destroying Semaphores

Create Semaphore (Data Communication>>Synchronization>>Semaphore palette) looks up an existing semaphore or creates a new semaphore and returns a refnum (see Figure 13.102). You can use this refnum when calling other Semaphore VIs.

Figure 13.102. Create Semaphore


Destroy Semaphore (Data Communication>>Synchronization>>Semaphore palette) destroys the specified semaphore (see Figure 13.103). All Acquire Semaphore VIs that are currently waiting on this semaphore time out immediately and return an error.

Figure 13.103. Destroy Semaphore


Acquiring (Locking) and Releasing (Unlocking) Semaphores

Acquire Semaphore (Data Communication>>Synchronization>>Semaphore palette) acquires (locks) access to a semaphore (see Figure 13.104).

Figure 13.104. Acquire Semaphore


If the semaphore is already acquired by the maximum number of tasks, the VI waits ms timeout milliseconds before timing out. If the semaphore becomes available during the wait, timed out is FALSE. If the semaphore does not become available or semaphore is not valid, timed out is TRUE. The count on a semaphore is incremented each time Acquire Semaphore executes, even if the task acquiring the semaphore has already acquired it once. Acquiring the same semaphore twice without an intervening call to Release Semaphore generally results in incorrect behavior, such as corrupted data values.

This VI attempts to execute even if the error in parameter contains an error.

Release Semaphore (Data Communication>>Synchronization>>Semaphore palette) releases access to a semaphore (see Figure 13.105). If Acquire Semaphore is waiting for the semaphore this VI releases, it stops waiting and continues execution.

Figure 13.105. Release Semaphore


To ensure correct functionality, call Release Semaphore later in the dataflow from Acquire Semaphore. LabVIEW protects the code between Acquire Semaphore and the Release Semaphore, so only as many parallel tasks can run simultaneously with the protected code as the size of the semaphore.

If a semaphore is already acquired and you call Release Semaphore without an Acquire Semaphore preceding it somewhere earlier in the dataflow, LabVIEW makes the semaphore available for another Acquire Semaphore to proceed, which violates the idea of semaphores protecting shared resources. For most use cases, this results in incorrect behavior, but LabVIEW cannot detect the situation for you.

This VI attempts to execute even if the error in parameter contains an error.

If a semaphore is currently unacquired, Release Semaphore returns error code 1111.

Obtaining Semaphore Status Information

Get Semaphore Status (Data Communication>>Synchronization>>Semaphore palette) returns current status information of a semaphore (see Figure 13.106).

Figure 13.106. Get Semaphore Status


Not A Semaphore (Data Communication>> Synchronization>>Semaphore palette) returns TRUE if semaphore is not a valid semaphore refnum. Note that (unlike with queue and notifier references) you cannot use the Not A Number/Path/Refnum function with a semaphore refnum. You must use the Not a Semaphore function for this purpose (see Figure 13.107).

Figure 13.107. Not A Semaphore


Semaphore Examples and Hints

For more examples showing how to use semaphores, look inside examples\general\semaphore.llb, found beneath your LabVIEW installation.

And, here are some final hints for using semaphores:

  • Use a semaphore to lock and unlock a shared resource that can only be accessed by one location at a time (or by a fixed number of locations at a time).

  • You cannot use the Not a Number/Path/Refnum function with a semaphore refnum. You must use the Not a Semaphore function for this purpose.

  • You can obtain a reference to a named semaphore in multiple locations in your application. Just wire the semaphore name into the name input of the Create Semaphore function.

  • Make sure to call Destroy Semaphore only once on a semaphore, and only when you are ready to destroy it. Note that each instance of a named semaphore uses the same reference. If you destroy any instance of a named semaphore, it will destroy it for all users. This is not the same behavior as queues and notifiers. (Note that queues and notifiers have a Release function, whereas semaphores have a Destroy function. Also, note that the Release Semaphore function does not release the reference, but rather releases the semaphore/lock.)

What would happen if semaphores did have data? What if the Acquire Semaphore function read the data and the Release Semaphore function wrote the data? This is exactly what the traditional Graphical Object-Oriented Programming (GOOP) framework does. You can learn more about GOOP and Object-Oriented Programming in Appendix D, "LabVIEW Object-Oriented Programming."


Rendezvous

The VIs found on the Rendezvous palette (shown in Figure 13.108) allow you to synchronize two or more separate, parallel tasks at specific points of execution. Each task that reaches the rendezvous waits until the specified number of tasks are waiting, at which point all tasks proceed with execution.

Figure 13.108. Rendezvous palette


Unlike a queue or a notifier, a rendezvous has no data. Rather, it is used purely for synchronizationto cause parallel tasks to all wait at a specific point before proceeding. Figure 13.109 shows a typical use case where a rendezvous is used to synchronize parallel tasks in separate loops. When this code executes, the loops will run at the rate of the slowest loop, due to the presence of the Wait at Rendezvous function.

Figure 13.109. Rendezvous Example.vi showing how to synchronize parallel tasks


You will learn more about the rendezvous functions next.

Creating and Destroying Rendezvous

Create Rendezvous (Data Communication>>Synchronization>>Rendezvous palette) looks up an existing rendezvous or creates a new rendezvous and returns a refnum (see Figure 13.110). You can use this refnum when calling other Rendezvous VIs.

Figure 13.110. Create Rendezvous


Destroy Rendezvous (Data Communication>>Synchronization>>Rendezvous palette) destroys the specified rendezvous (see Figure 13.111). All Wait at Rendezvous VIs that are currently waiting on this rendezvous time out immediately and return an error.

Figure 13.111. Destroy Rendezvous


Waiting on a Rendezvous

Wait at Rendezvous (Data Communication>> Synchronization>>Rendezvous palette) waits until a sufficient number of tasks have arrived at the rendezvous (see Figure 13.112).

Figure 13.112. Wait at Rendezvous


Resizing a Rendezvous

Resize Rendezvous (Data Communication >>Synchronization>>Rendezvous palette) changes the size of rendezvous by size change and returns new size (see Figure 13.113). Remember, the size of a rendezvous is the number of instances of Wait at Rendezvous that must be waiting before all instances can proceed.

Figure 13.113. Resize Rendezvous


Obtaining Rendezvous Status Information

Get Rendezvous Status (Data Communication>>Synchronization>>Rendezvous palette) returns current status information of a rendezvous (see Figure 13.114).

Figure 13.114. Get Rendezvous Status


Not A Rendezvous (Data Communication>>Synchronization>>Rendezvous palette) returns TRUE if rendezvous is not a valid rendezvous refnum. Note that (unlike with queue and notifier references) you cannot use the Not a Number/Path/Refnum function with a rendezvous refnum. You must use the Not a Rendezvous function for this purpose (see Figure 13.115).

Figure 13.115. Not A Rendezvous


Rendezvous Examples and Hints

For more examples showing how to use rendezvous, look inside examples\general\rendezvous.llb, found beneath your LabVIEW installation.

And, here are some final hints for using rendezvous:

  • Use a rendezvous to synchronize two or more separate, parallel tasks at specific points of execution. Each task that reaches the rendezvous waits until the specified number of tasks are waiting, at which point all tasks proceed with execution.

  • Make sure that rendezvous size is equal to the actual number of parallel tasks that you want to synchronize. Otherwise, you might not wait for all of the tasks to complete because you set the size to a value less than the number of parallel tasks, or you might wait forever because you set the size to a value larger than the number of parallel tasks.

  • You cannot use the Not a Number/Path/Refnum function with a rendezvous refnum. You must use the Not a Rendezvous function for this purpose.

  • You can obtain a reference to a named rendezvous in multiple locations in your application. Just wire the rendezvous name into the name input of the Create Rendezvous function.

  • Make sure to call Destroy Rendezvous only once on a rendezvous, and only when you are ready to destroy it. Note that each instance of a named rendezvous uses the same reference. If you destroy any instance of a named rendezvous, it will destroy it for all users. This is not the same behavior as queues and notifiers. (Note that queues and notifiers have a Release function, whereas rendezvous have a Destroy function.)

Occurrences

The VIs found on the Occurrences palette (shown in Figure 13.116) allow you to control separate, synchronous activities, in particular, when you want one VI or part of a block diagram to wait until another VI or part of a block diagram finishes a task without forcing LabVIEW to poll.

Figure 13.116. Occurrences palette


You can perform the same task using global variables (or local variables within the same VI), with one loop polling the global variable until its value changes. However, global variables use more overhead because the loop that waits uses execution time. With occurrences, the second loop becomes idle and does not use processor time. When the first loop sets the occurrence, LabVIEW activates the second loop and any other block diagrams that wait for the specified occurrence.

You are encouraged to use notifiers instead of occurrences for most operations. However, for some memory- and processor-intensive event-driven programs, occurrence might be the best choice.


Unlike the other synchronization VIs, there is no destroy function for occurrenceseach instance of the Generate Occurrence function acts similarly to a constant, outputting the same value each time it is called. Additionally, occurrences have no datathey are used purely for synchronization where you want to wait until an event occurs in some other location (or the wait function times out). Figure 13.117 shows Occurrence Example.vi (located in the EVERYONE\CH13 folder on the CD-ROM), an example where an occurrence is used synchronize two parallel tasks. In this example, Task B cannot execute until Task A completes, causing Set Occurrence to execute and therefore cause Wait on Occurrence (which was waiting for the occurrence to be set) to stop waiting.

Figure 13.117. Occurrence Example.vi showing how to synchronize parallel tasks


You will learn more about the occurrence functions next.

Creating Occurrences

Generate Occurrence (Data Communication>>Synchronization>>Occurrences palette) creates an occurrence that you can pass to the Wait on Occurrence and Set Occurrence functions (see Figure 13.118).

Figure 13.118. Generate Occurrence


Ordinarily, only one Generate Occurrence function is wired to any set of Wait on Occurrence and Set Occurrence functions. You can wire a Generate Occurrence function to any number of Wait on Occurrence and Set Occurrence functions. You do not have to have the same number of Wait on Occurrence and Set Occurrence functions.

Unlike other synchronization VIs (such as queues, notifiers, etc.), each Generate Occurrence function on a block diagram represents a single, unique occurrence. In this way, the Generate Occurrence function is similar to a constant. When a VI is running, every time a Generate Occurrence function executes, the function produces the same value. For example, if you place a Generate Occurrence function inside of a loop, the value produced by the Generate Occurrence function is the same for every iteration of the loop. If you place a Generate Occurrence function on the block diagram of a reentrant VI, the Generate Occurrence function produces a different value for each caller.

Waiting on and Setting Occurrences

Wait on Occurrence (Data Communication>>Synchronization>>Occurrences palette) waits for the Set Occurrence function to set or trigger the given occurrence (see Figure 13.119).

Figure 13.119. Wait on Occurrence


Set Occurrence (Data Communication>>Synchronization>>Occurrences palette) triggers the specified occurrence. All nodes that are waiting for this occurrence stop waiting (see Figure 13.120).

Figure 13.120. Set Occurrence


Occurrence Examples and Hints

For more examples showing how to use occurrences, look inside examples\general\occurrence.llb, found beneath your LabVIEW installation.

And, here are some final hints for using occurrences:

  • Generally, you should use occurrences only for memory and performance optimization. Try using notifiers instead of occurrences.

  • Occurrences don't have a destroy function (like other synchronization functions). Each Generate Occurrence function acts as a constant, outputting the same occurrence reference each time it is called.

First Call?

The First Call? function (see Figure 13.121) is found on the Data Communication>>Synchronization palette. The Boolean output of this function indicates that a subVI or section of a block diagram is running for the first time.

Figure 13.121. First Call?


The First Call? function (Data Communication>>Synchronization palette) returns TRUE only the first time you call it after you click the Run button. You can place the First Call? function in multiple locations within a VI. The function returns TRUE the first time the section of the block diagram in which it is placed runs.

This function is useful if you want to run a subVI or a section of a block diagram within a loop or Case Structure only once when the VI runs.

First Call? returns TRUE the first time the VI runs after the first top-level caller starts running, such as when the Run button is clicked or the Run VI method executes. If a second top-level caller calls the VI while the first top-level caller is still running, First Call? does not return TRUE a second time. After all the top-level callers become idle and a top-level caller starts again, First Call? returns TRUE the first time the VI runs after the idle state. Reentrant VIs (discussed in Chapter 15) have an instance per data space. Therefore, a shared reentrant VI returns TRUE for each data space instance the first time its top-level caller calls it.




LabVIEW for Everyone. Graphical Programming Made Easy and Fun
LabVIEW for Everyone: Graphical Programming Made Easy and Fun (3rd Edition)
ISBN: 0131856723
EAN: 2147483647
Year: 2006
Pages: 294

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net