Randomizing Functions in BCX are not optimized for a multi-threading environment

Started by Saleh, October 01, 2025, 03:09:20 AM

Previous topic - Next topic

MrBcx

Quote from: Saleh on October 02, 2025, 04:39:37 AMThank you so much, Kevin. That suggestion was incredibly helpful. As you said: "uses a thread-safe replacement for RND2()." I gave it a try, and it worked beautifully. I really appreciate your insight and the clarity of your explanation—it saved me a lot of time and frustration.

Hi Saleh --

I'm glad it worked out for you -- also, thank you for your kind words.

Saleh

QuoteThis seems to be working - give it a try, maybe it will fit your needs.
It uses a thread-safe replacement for RND2() which itself uses the thread-safe
CryptGenRandom() instead of the non-thread-safe rand().

Thank you so much, Kevin. That suggestion was incredibly helpful. As you said: "uses a thread-safe replacement for RND2()." I gave it a try, and it worked beautifully. I really appreciate your insight and the clarity of your explanation—it saved me a lot of time and frustration.

MrBcx

Saleh,

This seems to be working - give it a try, maybe it will fit your needs.
It uses a thread-safe replacement for RND2() which itself uses the thread-safe
CryptGenRandom() instead of the non-thread-safe rand().



SET UsedChars[] AS CHAR
    48,  49,  50,  51,  52,  53,  54,
    55,  56,  57, 65,  66,  67,
    68,  69, 70
END SET

RANDOMIZE

DIM TH_NUMBER AS ULONG
DIM CORE_NUM AS INTEGER, ITH AS INTEGER

CORE_NUM =  5
DIM hThread[100] AS HANDLE

FOR ITH = 0 TO CORE_NUM
    hThread[ITH] = BCX_THREAD(DOWORK)
NEXT ITH

FOR ITH = 0 TO CORE_NUM
    BCX_THREADWAIT(hThread[ITH])
NEXT ITH
PAUSE

SUB DOWORK
    TH_NUMBER = TH_NUMBER + 1
    DIM priv_hex$
    DIM comp$
    DIM uncomp$
    DIM x$, y$

    priv_hex$ = KeyGenIt$(17)

    PRINT "Private: "; priv_hex; ":"; TH_NUMBER

    '''''''''''''''''''''''''''''''''''''''
    BCX_THREADEND
END SUB


FUNCTION KeyGenIt$ (BYVAL sz AS INTEGER)
    DIM J AS INTEGER

    DIM Jx$ * sz+1
    FOR J = 0 TO sz
        Jx[J] =  UsedChars[CINT(TS_Rnd2(0, 15))]
    NEXT J
    Jx [sz] = 0
    FUNCTION = Jx$
END FUNCTION


'  Thread-safe replacement for RND2()
FUNCTION TS_Rnd2(Minimum AS DOUBLE, Maximum AS DOUBLE) AS DOUBLE
    DIM RandomValue AS INT
    DIM MinInt AS INT
    DIM MaxInt AS INT
    DIM Range AS INT

    MinInt = Minimum
    MaxInt = Maximum
    Range  = MaxInt - MinInt + 1

    IF Range <= 0 THEN
        FUNCTION = Minimum
    END IF

    RandomValue = RND_S()
    IF RandomValue < 0 THEN
        FUNCTION = Minimum
    END IF

    FUNCTION = (DOUBLE)(MinInt + (CLNG(RandomValue) MOD Range))
END FUNCTION




FUNCTION RND_S AS INT         '  Thread-safe and re-entrant
    '*************************************************************
    ' Returns a cryptographically secure 32-bit random number.
    ' Uses Windows CryptoAPI (CryptGenRandom).
    '*************************************************************
    #include <wincrypt.h>

    STATIC hProv AS HCRYPTPROV
    STATIC isInit AS INT
    DIM n AS UINT
    DIM ok AS INT

    IF isInit = 0 THEN
        ok = CryptAcquireContext(&hProv, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT)
        IF ok = FALSE THEN
            FUNCTION = -1
        END IF
        isInit = 1
    END IF

    ok = CryptGenRandom(hProv, SIZEOF(n), (BYTE*)&n)
    IF ok = FALSE THEN
        FUNCTION = -1
    END IF

    FUNCTION =  n
END FUNCTION


MrBcx

Hi Saleh,

RND2() uses the c standard runtime function rand() which is not thread safe.

In The meantime ...

You could share the BCX runtime code for RND2() with several of the AI's and
ask each to devise a thread-safe replacement, hopefully resulting in something
useful.

Saleh

    SET UsedChars[] AS CHAR
      48,  49,  50,  51,  52,  53,  54,
      55,  56,  57, 65,  66,  67,
      68,  69, 70
    END SET
    Randomize
     Dim TH_NUMBER AS ULONG
     DIM CORE_NUM AS INTEGER, ITH AS INTEGER

     CORE_NUM =  5
     DIM hThread[100] AS HANDLE
     FOR ITH = 0 TO CORE_NUM
        hThread[ITH] = BCX_THREAD(DOWORK)
     NEXT ITH
 
     FOR ITH = 0 TO CORE_NUM
        BCX_THREADWAIT(hThread[ITH])
     NEXT ITH

     SUB DOWORK
        TH_NUMBER = TH_NUMBER + 1
        dim priv_hex$
        dim comp$
        dim uncomp$
        dim x$, y$

        priv_hex$ = KeyGenIt$(17)


        PRINT "Private: "; priv_hex; ":"; TH_NUMBER
        '''''''''''''''''''''''''''''''''''''''
        BCX_THREADEND
     END SUB
    Function KeyGenIt$(ByVal sz As Integer)
        Dim J As Integer

        DIM Jx[sz+1] As CHAR     
        For J = 0 To sz
            Jx[J] =  UsedChars[RND2(0,15)]
        Next J
        Jx [sz] = 0
        FUNCTION = Jx
    End Function




RND2(0,15) is not work here.
It seems that BCX should have had a mechanism like a mutex to protect shared resources in multithreaded environments. For example, in this case, when the RND2 function is already processing, it shouldn't be called again by other threads. I'm not entirely sure—maybe I'm wrong—but it feels like everything in my code ultimately traces back to the RND2 function.