Announcement

Collapse

Forum Guidelines

This forum is for finished source code that is working properly. If you have questions about this or any other source code, please post it in one of the Discussion Forums, not here.
See more
See less

Implementing a JobQueue (NT/W2k) example

Collapse
X
 
  • Filter
  • Time
  • Show
Clear All
new posts

  • Implementing a JobQueue (NT/W2k) example

    Here's an example using QueueUserAPC and SleepEx to implement
    a JobQueue (only NT/W2000). Updated 7-Feb-2002
    Code:
    #IF 0
    *******************************************************
    * ' Illustrates a Job Queue using QueueUserAPC
    * ' An easy way to implement a serialized Job Queue
    * ' running on a single thread
    * '
    * ' Written  : Florent Heyworth
    * ' Date     : 22-Apr-2001
    * ' Updated  : 07-Feb-2002
    * '
    * ' Notes of course you could use an array() in a
    * ' function for the same functionality in this example
    * ' However in a multi-threaded application this
    * ' becomes *very* useful since any thread can queue
    * ' a job to the job queue using the JobQueue's thread
    * ' handle (just make it global or pass it on the
    * ' stack) - You could use messages but I find this
    * ' useful...
    * '
    * ' Updates: changed example to FIFO and LIFO queues
    * '          changed SleepEx parameter
    * '
    *******************************************************
    #ENDIF
     
    #INCLUDE "win32api.inc"
     
    TYPE T_JOB
        szChars AS ASCIIZ * 41
        lJobNum AS LONG
    END TYPE
     
    %APC_EXIT = -1
    %APC_DO_NOTHING = 0
      
    FUNCTION JobQueue_Lifo( BYVAL lArg AS LONG ) AS LONG
        'last in first out queue
        LOCAL lAlert AS LONG
        LOCAL dwWait AS DWORD
        LOCAL t AS T_JOB PTR
     
        lAlert = 1          'alertable
        dwWait = %INFINITE  'forever     [img]http://www.powerbasic.com/support/forums/smile.gif[/img]
        IF lArg = %APC_EXIT THEN
            dwWait = 0  'no wait
            lAlert = 0  'non-alertable
        END IF
     
        'Changed passing of lAlert parameter
        CALL SleepEx( dwWait, lAlert ) 'wait until another APC is queued
     
        IF lArg <> %APC_DO_NOTHING AND lArg <> %APC_EXIT THEN
            SLEEP 1000 ' simulate some real processing
            t = lArg
            PRINT "Chars: " @t.szChars
            PRINT "Jobnr: " + FORMAT$( @t.lJobNum )
            CALL HeapFree( GetProcessHeap(), 0, BYVAL t ) 'free dynamically allocated structure
        END IF
     
    END FUNCTION
     
    FUNCTION JobQueue_Fifo( BYVAL lArg AS LONG ) AS LONG
        'First in first out queue
        LOCAL lAlert AS LONG
        LOCAL dwWait AS DWORD
        LOCAL t AS T_JOB PTR
     
        lAlert = 1          'alertable
        dwWait = %INFINITE  'forever     [img]http://www.powerbasic.com/support/forums/smile.gif[/img]
        IF lArg = %APC_EXIT THEN
            dwWait = 0  'no wait
            lAlert = 0  'non-alertable
        END IF
     
        IF lArg <> %APC_DO_NOTHING AND lArg <> %APC_EXIT THEN
            SLEEP 1000 ' simulate some real processing
            t = lArg
            PRINT "Chars: " @t.szChars
            PRINT "Jobnr: " + FORMAT$( @t.lJobNum )
            CALL HeapFree( GetProcessHeap(), 0, BYVAL t ) 'free dynamically allocated structure
        END IF
         
        'changed passing of lAlert parameter
        CALL SleepEx( dwWait, lAlert ) 'wait until another APC is queued
     
    END FUNCTION
     
    FUNCTION PBMAIN() AS LONG
        LOCAL hThread AS LONG
        LOCAL hResult AS LONG
        LOCAL lArg AS LONG
        LOCAL lDummy AS LONG
        LOCAL i AS LONG
        LOCAL t AS T_JOB PTR
     
        '///////////////////////////////////////////////////////////
        ' FIFO queue DEMO
        '///////////////////////////////////////////////////////////
        THREAD CREATE Jobqueue_Fifo( %APC_DO_NOTHING ) TO hThread
        SLEEP 200 'give the thread a chance
     
        STDOUT "Fifo Queue"
        FOR i = 0 TO 100
            t = HeapAlloc( GetProcessHeap(), %HEAP_ZERO_MEMORY, SIZEOF(@t) )
            @t.szChars = STRING$( SIZEOF(@t.szChars)-1, CHR$(i + 33) )
            @t.lJobNum = i
            IF QueueUserAPC( CODEPTR(JobQueue_Fifo), hThread, t ) = %FALSE THEN
                STDOUT "QueueUserAPC() failed exiting loop"
                EXIT FOR
            END IF
     
        NEXT
     
        SLEEP 5000 'simulate items queued and a pause
        FOR i = 100 TO 200
            t = HeapAlloc( GetProcessHeap(), %HEAP_ZERO_MEMORY, SIZEOF(@t) )
            @t.szChars = STRING$( SIZEOF(@t.szChars)-1, CHR$(i - 33) )
            @t.lJobNum = i
            IF QueueUserAPC( CODEPTR(JobQueue_Fifo), hThread, t ) = %FALSE THEN
                STDOUT "QueueUserAPC() failed exiting loop"
                EXIT FOR
            END IF
     
        NEXT
     
        IF QueueUserAPC( CODEPTR(JobQueue_Fifo), hThread, %APC_EXIT ) THEN
            PRINT "Called exit APC"
        ELSE
            PRINT "Called exit APC failed"
        END IF
     
        CALL WaitForSingleObject( hThread, %INFINITE ) 'wait until all jobs are finished
        THREAD CLOSE hThread TO hResult
     
      
        '///////////////////////////////////////////////////////////
        ' LIFO queue DEMO
        '///////////////////////////////////////////////////////////
        THREAD CREATE Jobqueue_Lifo( %APC_DO_NOTHING ) TO hThread
        SLEEP 200 'give the thread a chance
      
        STDOUT "Lifo Queue"
        FOR i = 0 TO 100
            t = HeapAlloc( GetProcessHeap(), %HEAP_ZERO_MEMORY, SIZEOF(@t) )
            @t.szChars = STRING$( SIZEOF(@t.szChars)-1, CHR$(i + 33) )
            @t.lJobNum = i
            IF QueueUserAPC( CODEPTR(JobQueue_Lifo), hThread, t ) = %FALSE THEN
                STDOUT "QueueUserAPC() failed exiting loop"
                EXIT FOR
            END IF
     
        NEXT
     
        SLEEP 5000 'simulate items queued and a pause
        FOR i = 100 TO 200
            t = HeapAlloc( GetProcessHeap(), %HEAP_ZERO_MEMORY, SIZEOF(@t) )
            @t.szChars = STRING$( SIZEOF(@t.szChars)-1, CHR$(i - 33) )
            @t.lJobNum = i
            IF QueueUserAPC( CODEPTR(JobQueue_Lifo), hThread, t ) = %FALSE THEN
                STDOUT "QueueUserAPC() failed exiting loop"
                EXIT FOR
            END IF
     
        NEXT
     
        IF QueueUserAPC( CODEPTR(JobQueue_Lifo), hThread, %APC_EXIT ) THEN
            PRINT "Called exit APC"
        ELSE
            PRINT "Called exit APC failed"
        END IF
      
        CALL WaitForSingleObject( hThread, %INFINITE ) 'wait until all jobs are finished
        THREAD CLOSE hThread TO hResult
     
        PRINT "Job well done"
        WAITKEY$
    END FUNCTION
    Cheers

    Florent



    [This message has been edited by Florent Heyworth (edited February 07, 2002).]

  • #2
    Florent,

    I've found that this hangs after the processing the 42nd job.
    The JobQueue goes to sleep and never wakes up. I’ve tried
    delaying the calls to QueueUserAPC thinking that maybe there
    was a limit on the queue but that does not help. I’ve tested
    this program on a couple Win2K machines but it fails on each.
    I’m using PBCC 2.1 w/ the latest win32api.inc. Any ideas?

    Thanks!

    ------------------

    Comment


    • #3
      Hmm can you confirm that the above example fails as is
      after the 42nd iteration? It runs fine on my pcs. Ill
      try to reproduce that behaviour when I get back to work.

      FWIW, I've used this technique in numerous production programs
      and have never seen any problems with it. What systems
      did you try it on (Service pack, etc, number of CPUs).

      Ill have a look tomorrow at the newest win32api.inc to see
      if that could be the problem.

      Cheers

      Florent

      ------------------

      Comment


      • #4
        Florent,

        I’ve moved this discussion to the PowerBASIC for Windows under
        the "Sending Messages Between (Worker) Threads" thread.
        Please post your reply there.

        Thanks!

        BTW: I’m running Win2K SP2, single processor.


        ------------------

        Comment


        • #5
          Updated source code

          ------------------

          Comment

          Working...
          X