' Producer-consumer with THREAD synchronization
#COMPILE EXE
#DIM ALL

CONST BUFFER_SIZE = 8
CONST NUM_ITEMS = 16
GLOBAL gBuf0  AS LONG

GLOBAL gBuf1  AS LONG

GLOBAL gBuf2  AS LONG

GLOBAL gBuf3  AS LONG
GLOBAL gBuf4  AS LONG
GLOBAL gBuf5  AS LONG
GLOBAL gBuf6  AS LONG
GLOBAL gBuf7  AS LONG
GLOBAL gHead  AS LONG
GLOBAL gTail  AS LONG
GLOBAL gCount  AS LONG
SUB InitBuffer()
    gHead = 0
    gTail = 0
    gCount = 0
    gBuf0 = 0
    gBuf1 = 0
    gBuf2 = 0
    gBuf3 = 0
    gBuf4 = 0
    gBuf5 = 0
    gBuf6 = 0
    gBuf7 = 0
END SUB

SUB ReadBuf(BYVAL idx AS LONG, BYREF val AS LONG)
    IF idx = 0 THEN val = gBuf0
    IF idx = 1 THEN val = gBuf1
    IF idx = 2 THEN val = gBuf2
    IF idx = 3 THEN val = gBuf3
    IF idx = 4 THEN val = gBuf4
    IF idx = 5 THEN val = gBuf5
    IF idx = 6 THEN val = gBuf6
    IF idx = 7 THEN val = gBuf7
END SUB

SUB WriteBuf(BYVAL idx AS LONG, BYVAL val AS LONG)
    IF idx = 0 THEN gBuf0 = val
    IF idx = 1 THEN gBuf1 = val
    IF idx = 2 THEN gBuf2 = val
    IF idx = 3 THEN gBuf3 = val
    IF idx = 4 THEN gBuf4 = val
    IF idx = 5 THEN gBuf5 = val
    IF idx = 6 THEN gBuf6 = val
    IF idx = 7 THEN gBuf7 = val
END SUB

FUNCTION BufferFull() AS LONG
    IF gCount >= BUFFER_SIZE THEN FUNCTION = 1
    FUNCTION = 0
END FUNCTION

FUNCTION BufferEmpty() AS LONG
    IF gCount = 0 THEN FUNCTION = 1
    FUNCTION = 0
END FUNCTION

SUB PutItem(BYVAL itemVal AS LONG)
    LOCAL iter AS LONG
    iter = 0
    DO
        IF BufferFull() = 0 THEN
            WriteBuf(gHead, itemVal)
            gHead = (gHead + 1) MOD BUFFER_SIZE
            gCount = gCount + 1
            PRINT "Put: "; itemVal; " count="; gCount
            EXIT SUB
        END IF
        iter = iter + 1
        IF iter > 100 THEN PRINT "Timeout put "; itemVal: EXIT SUB
    LOOP
END SUB

FUNCTION GetItem() AS LONG
    LOCAL iter  AS LONG
    LOCAL val  AS LONG
    iter = 0
    DO
        IF BufferEmpty() = 0 THEN
            ReadBuf(gTail, val)
            gTail = (gTail + 1) MOD BUFFER_SIZE
            gCount = gCount - 1
            PRINT "Get: "; val; " count="; gCount
            FUNCTION = val
        END IF
        iter = iter + 1
        IF iter > 100 THEN PRINT "Timeout get": FUNCTION = -1
    LOOP
END FUNCTION

SUB RunSimulation()
    InitBuffer()
    PRINT "Buffer size="; BUFFER_SIZE; " items="; NUM_ITEMS
    LOCAL i AS LONG
    FOR i = 1 TO NUM_ITEMS
        PutItem(i * 10)
    NEXT i
    FOR i = 1 TO NUM_ITEMS
        LOCAL v AS LONG
        v = GetItem()
    NEXT i
    PRINT "Final count="; gCount
END SUB

SUB ThreadPlan()
    PRINT ""
    PRINT "With THREAD CREATE:"
    PRINT "  Producer thread -> Puts items 1-8"
    PRINT "  Consumer thread -> Gets items"
    PRINT "  Synchronized via busy-wait on gCount"
END SUB

FUNCTION PBMAIN() AS LONG
    PRINT "=== Producer-Consumer Demo ==="
    RunSimulation()
    ThreadPlan()
    PRINT "=== End Producer-Consumer ==="
    FUNCTION = 0
END FUNCTION
