' Worker thread pool with job queue
#COMPILE EXE
#DIM ALL

%JOB_COMPUTE = 1
%JOB_FILEIO = 2
%JOB_NETWORK = 3

GLOBAL gKind0  AS LONG

GLOBAL gKind1  AS LONG

GLOBAL gKind2  AS LONG

GLOBAL gKind3  AS LONG
GLOBAL gKind4  AS LONG
GLOBAL gKind5  AS LONG
GLOBAL gKind6  AS LONG
GLOBAL gKind7  AS LONG
GLOBAL gParam0  AS LONG
GLOBAL gParam1  AS LONG
GLOBAL gParam2  AS LONG
GLOBAL gParam3  AS LONG
GLOBAL gParam4  AS LONG
GLOBAL gParam5  AS LONG
GLOBAL gParam6  AS LONG
GLOBAL gParam7  AS LONG
GLOBAL gResult0  AS LONG
GLOBAL gResult1  AS LONG
GLOBAL gResult2  AS LONG
GLOBAL gResult3  AS LONG
GLOBAL gResult4  AS LONG
GLOBAL gResult5  AS LONG
GLOBAL gResult6  AS LONG
GLOBAL gResult7  AS LONG
GLOBAL gCount  AS LONG
GLOBAL gNextJob  AS LONG
SUB InitPool()
    gCount = 0
    gNextJob = 0
END SUB

FUNCTION AddJob(BYVAL kind AS LONG, BYVAL param AS LONG) AS LONG
    IF gCount >= 8 THEN FUNCTION = -1
    IF gCount = 0 THEN gKind0 = kind: gParam0 = param: gResult0 = 0
    IF gCount = 1 THEN gKind1 = kind: gParam1 = param: gResult1 = 0
    IF gCount = 2 THEN gKind2 = kind: gParam2 = param: gResult2 = 0
    IF gCount = 3 THEN gKind3 = kind: gParam3 = param: gResult3 = 0
    IF gCount = 4 THEN gKind4 = kind: gParam4 = param: gResult4 = 0
    IF gCount = 5 THEN gKind5 = kind: gParam5 = param: gResult5 = 0
    IF gCount = 6 THEN gKind6 = kind: gParam6 = param: gResult6 = 0
    IF gCount = 7 THEN gKind7 = kind: gParam7 = param: gResult7 = 0
    gCount = gCount + 1
    FUNCTION = gCount
END FUNCTION

SUB GetKind(BYVAL idx AS LONG, BYREF k AS LONG)
    IF idx = 0 THEN k = gKind0
    IF idx = 1 THEN k = gKind1
    IF idx = 2 THEN k = gKind2
    IF idx = 3 THEN k = gKind3
    IF idx = 4 THEN k = gKind4
    IF idx = 5 THEN k = gKind5
    IF idx = 6 THEN k = gKind6
    IF idx = 7 THEN k = gKind7
END SUB

SUB GetParam(BYVAL idx AS LONG, BYREF p AS LONG)
    IF idx = 0 THEN p = gParam0
    IF idx = 1 THEN p = gParam1
    IF idx = 2 THEN p = gParam2
    IF idx = 3 THEN p = gParam3
    IF idx = 4 THEN p = gParam4
    IF idx = 5 THEN p = gParam5
    IF idx = 6 THEN p = gParam6
    IF idx = 7 THEN p = gParam7
END SUB

SUB SetResult(BYVAL idx AS LONG, BYVAL r AS LONG)
    IF idx = 0 THEN gResult0 = r
    IF idx = 1 THEN gResult1 = r
    IF idx = 2 THEN gResult2 = r
    IF idx = 3 THEN gResult3 = r
    IF idx = 4 THEN gResult4 = r
    IF idx = 5 THEN gResult5 = r
    IF idx = 6 THEN gResult6 = r
    IF idx = 7 THEN gResult7 = r
END SUB

SUB GetResult(BYVAL idx AS LONG, BYREF r AS LONG)
    IF idx = 0 THEN r = gResult0
    IF idx = 1 THEN r = gResult1
    IF idx = 2 THEN r = gResult2
    IF idx = 3 THEN r = gResult3
    IF idx = 4 THEN r = gResult4
    IF idx = 5 THEN r = gResult5
    IF idx = 6 THEN r = gResult6
    IF idx = 7 THEN r = gResult7
END SUB

SUB ExecJob(BYVAL idx AS LONG)
    LOCAL k  AS LONG
    LOCAL p  AS LONG
    LOCAL r  AS LONG
    GetKind(idx, k)
    GetParam(idx, p)
    r = 0
    IF k = %JOB_COMPUTE THEN
        LOCAL i AS LONG
        FOR i = 1 TO p
            r = r + i
        NEXT i
    END IF
    IF k = %JOB_FILEIO THEN r = p * 2
    IF k = %JOB_NETWORK THEN r = p * 3
    SetResult(idx, r)
    PRINT "Job #"; idx; " kind="; k; " result="; r
END SUB

SUB RunPool(BYVAL numWorkers AS LONG)
    PRINT "Running "; numWorkers; " workers on "; gCount; " jobs"
    LOCAL i AS LONG
    FOR i = 0 TO gCount - 1
        LOCAL assigned AS LONG
        assigned = i MOD numWorkers
        PRINT "  Job #"; i; " -> Worker "; assigned
        ExecJob(i)
    NEXT i
    LOCAL total AS LONG
    total = 0
    FOR i = 0 TO gCount - 1
        LOCAL r AS LONG
        GetResult(i, r)
        total = total + r
    NEXT i
    PRINT "Total: "; total
END SUB

SUB PoolDemo()
    InitPool()
    AddJob(%JOB_COMPUTE, 100)
    AddJob(%JOB_FILEIO, 50)
    AddJob(%JOB_NETWORK, 30)
    AddJob(%JOB_COMPUTE, 200)
    AddJob(%JOB_FILEIO, 75)
    AddJob(%JOB_COMPUTE, 150)
    RunPool(3)
END SUB

FUNCTION PBMAIN() AS LONG
    PRINT "=== Thread Pool Demo ==="
    PoolDemo()
    PRINT "=== End Thread Pool ==="
    FUNCTION = 0
END FUNCTION
