CondWait

Stops execution of current thread until some condition becomes true

Syntax
   Declare Sub CondWait ( ByVal handle As Any Ptr, ByVal mutex As Any Ptr )

Usage
   CondWait ( handle, mutex )

Parameters
   handle
      The handle of a conditional variable.
   mutex
      The mutex associated with this conditional variable, which must be 
      locked when testing the condition and calling CondWait.

Description
   Function that stops the thread where it is called until some other 
   thread  CondSignals or CondBroadcasts  the handle.

   Once the conditional variable is created with CondCreate and the threads 
   are started, one of more of them (including the implicit main thread 
   executing main program) can be set to CondWait for the conditional; they 
   will be stopped until some other thread CondSignals that the waiting 
   thread can restart. CondBroadcast can be used to restart all threads 
   waiting for the conditional. At the end of the program CondDestroy must 
   be used to avoid leaking resources in the OS.

   When calling CondWait, mutex should already be locked (using the same 
   mutex as one used with CondSignal or CondBroadcast). An atomic unlock of 
   the mutex and wait on the conditional variable will occur. The calling 
   thread execution is suspended and does not consume any CPU time until 
   the condition variable is signaled. When the condition variable becomes 
   signaled, mutex will be locked again and then execution will return to 
   the thread after the CondWait call, but with the mutex owned by the 
   caller. The caller is then responsible for unlocking mutex in order to 
   complete CondWait subroutine so that execution after the CondWait call 
   can then resume.

   Note: It is a good habit to use CondWait in a protected way against 
   eventual spurious wakeups.
   For that, CondWait is put within a loop for checking that a Boolean 
   predicate is indeed true (predicate set true by another thread just 
   before executing CondSignal or CondBroadcast) when the thread has 
   finished waiting:
      signal-caller:
         predicate = true
         Condsignal(handle)
      waiting-called:
         While predicate <> true
            Condwait(handle, mutex)
         Wend
         predicate = false
      the loop can terminate only when the predicate is true.
   On the other hand, if the predicate is already true before the thread 
   reaches the loop, CondWait is downright skipped (allowing to take into 
   account a case of CondSignal or CondBroadcast that would have been lost 
   otherwise, because prematurely executed in a second thread before the 
   first thread is really waiting for this).
   See example below for detailed coding.

Example
   See also CondCreate and CondSignal

   ' This simple example code demonstrates the use of several condition variable routines.
   ' The main routine creates three threads.
   ' Two of the threads update a "count" variable.
   ' The third thread waits until the count variable reaches a specified value.

   #define numThread  3
   #define countThreshold 6

   Dim Shared As Integer count = 0
   Dim Shared As Any Ptr countMutex
   Dim Shared As Any Ptr countThresholdCV
   Dim As Any Ptr threadID(0 To numThread-1)
   Dim Shared As Integer ok = 0

   Sub threadCount (ByVal p As Any Ptr)
      Print "Starting threadCount(): thread#" & p
      Do
         Print "threadCount(): thread#" & p & ", locking mutex"
         MutexLock(countMutex)
         count += 1
         ' Check the value of count and signal waiting thread when condition is reached.
         ' Note that this occurs while mutex is locked.
         If count >= countThreshold Then
            If count = countThreshold Then
               Print "threadCount(): thread#" & p & ", count = " & count & ", threshold reached, unlocking mutex"
               ok = 1
               CondSignal(countThresholdCV)
            Else
               Print "threadCount(): thread#" & p & ", count = " & count & ", threshold exceeded, unlocking mutex"
            End If
            MutexUnlock(countMutex)
            Exit Do
         End If
         Print "threadCount(): thread#" & p & ", count = " & count & ", unlocking mutex"
         MutexUnlock(countMutex)
         Sleep 100, 1
      Loop
   End Sub

   Sub threadWatch (ByVal p As Any Ptr)
      Print "Starting threadWatch(): thread#" & p & ", locking mutex, waiting for conditional"
      MutexLock(countMutex)
      ' Note that the Condwait routine will automatically and atomically unlock mutex while it waits.
      While ok = 0
         CondWait(countThresholdCV, countMutex)
      Wend
      Print "threadWatch(): thread#" & p & ", condition signal received"
      Print "threadWatch(): thread#" & p & ", count now = " & count & ", unlocking mutex"
      MutexUnlock(countMutex)
   End Sub

   ' Create mutex and condition variable
   countMutex = MutexCreate
   countThresholdCV = CondCreate
   ' Create threads
   threadID(0) = ThreadCreate(@threadWatch, Cast(Any Ptr, 1))
   threadID(1) = ThreadCreate(@threadCount, Cast(Any Ptr, 2))
   threadID(2) = ThreadCreate(@threadCount, Cast(Any Ptr, 3))
   ' Wait for all threads to complete
   For I As Integer = 0 To numThread-1
      ThreadWait(threadID(I))
      Print "Main(): Waited on thread#" & I+1 & " Done"
   Next I
   MutexDestroy(countMutex)
   CondDestroy(countThresholdCV)

Platform Differences
   * Condwait is not available with the DOS version / target of FreeBASIC, 
     because multithreading is not supported by DOS kernel nor the used 
     extender.
   * In Linux the threads are always started in the order they are 
     created, this can't be assumed in Win32. It's an OS, not a FreeBASIC 
     issue. 

Dialect Differences
   * Threading is not allowed in -lang qb

Differences from QB
   * New to FreeBASIC

See also
   * CondCreate
   * CondDestroy
   * CondBroadcast
   * CondSignal
   * MutexCreate
   * MutexLock
   * MutexUnlock
   * ThreadCreate

