05-28-2024, 01:41 AM
Hello all,
I have another test program that uses threads. This time it creates from 1 to 8 worker threads and they draw colored squares across the screen.
As before it needs a header file to setup threading. Its name is 'workers.h'
And the QB side is as follows. Its name is whatever you like.
I have another test program that uses threads. This time it creates from 1 to 8 worker threads and they draw colored squares across the screen.
As before it needs a header file to setup threading. Its name is 'workers.h'
Code: (Select All)
// workers.h
// Threading Header
#include "pthread.h"
// Only needed for the SIGTERM Constant
#include <signal.h>
#include <unistd.h>
#include <time.h>
#define RETRYCOUNT 5
// Initialize Threads
static pthread_t thread[9];
typedef struct thread_data {
int id;
} thread_data;
// Easy was to determine if a thread is running
bool threadRunning[] = {false,false,false,false,false,false,false,false,false,false};
// Setup Mutexes.
static pthread_mutex_t mutex[9];
// QB's names for the threaded Subs
// You can locate these in your ''qb64pe/internal/temp'' folder.
// I found these in the 'main.txt'
void SUB_WORKERTHREAD(int32*_SUB_WORKERTHREAD_LONG_ID);
// wrap the subs so that you can easily get the void* for pthread
void* RunWorker(void *arg){
thread_data *tdata=(thread_data *)arg;
int a = tdata->id;
SUB_WORKERTHREAD((int32*)&a);
}
// These are the commands that are accessed by you program
void invokeWorker(int id){
thread_data tdata;
tdata.id = id;
int icount = 0;
if (!threadRunning[id]) {
while(pthread_create( &thread[id], NULL, RunWorker, (void *)&tdata))
{
icount++;
if (icount > RETRYCOUNT){
return;
}
sleep(1);
};
pthread_mutex_init(&mutex[id], NULL);
threadRunning[id] = true;
}
sleep(1);
}
void joinThread(int id){
pthread_join(thread[id],NULL);
threadRunning[id] = false;
}
void exitThread(){
pthread_exit(NULL);
}
void killThread(int id){
if (threadRunning[id]) {
int iret = pthread_kill(thread[id], SIGTERM);
}
}
void lockThread(int id){
pthread_mutex_lock(&mutex[id]);
}
void unlockThread(int id){
pthread_mutex_unlock(&mutex[id]);
}
Code: (Select All)
DECLARE LIBRARY "./workers"
SUB invokeWorker (BYVAL id AS LONG) ' start Lines thread
SUB joinThread (BYVAL id AS LONG) ' wait til thread is finished
SUB exitThread ' must be called as thread exits
SUB killThread (BYVAL id AS LONG) ' kill the thread
SUB lockThread (BYVAL id AS LONG) ' mutex lock
SUB unlockThread (BYVAL id AS LONG) ' mutex unlock
END DECLARE
TYPE tWorker
xstart AS LONG
ystart AS LONG
xsize AS LONG
ysize AS LONG
xdir AS _BYTE
x AS LONG
y AS LONG
colour AS LONG
command AS LONG
sc AS LONG
img AS _MEM
offset AS _OFFSET
dly AS _BYTE
END TYPE
DIM indx AS LONG
DIM ky AS STRING
DIM AS INTEGER tc
_TITLE "Worker Thread Test"
SCREEN _NEWIMAGE(800, 600, 32)
DO
CLS
PRINT "How many worker threads? Low spec machines should start less than 4."
INPUT "(1 - 8, 0 to quit):"; tc
IF tc = 0 THEN SYSTEM
LOOP UNTIL tc >= 1 AND tc <= 8
tc = tc - 1
CLS
DIM SHARED AS tWorker worker(tc)
FOR indx = 0 TO tc
resetWorker indx
worker(indx).sc = _NEWIMAGE(worker(indx).xsize + 1, worker(indx).ysize + 1, 32)
worker(indx).img = _MEMIMAGE(worker(indx).sc)
NEXT
LOCATE 1
FOR indx = 0 TO tc
PRINT "Starting thread:"; indx
invokeWorker indx
NEXT
CLS
DO
ky = INKEY$
IF ky = "d" THEN
FOR indx = 0 TO tc
worker(indx).dly = NOT worker(indx).dly
NEXT
END IF
IF ky = "s" THEN
CLS
FOR indx = 0 TO tc
worker(indx).command = NOT worker(indx).command
IF worker(indx).command THEN
joinThread indx
ELSE
PRINT "Restarting thread:"; indx
_DISPLAY
invokeWorker indx
END IF
NEXT
CLS
END IF
IF ky = CHR$(27) THEN
FOR indx = 0 TO tc
worker(indx).command = -1
joinThread indx
SYSTEM
NEXT
END IF
FOR indx = 0 TO tc
_PRINTSTRING (indx * 100 + 10, 220), "Worker:" + STR$(indx)
_PUTIMAGE (indx * 100, 250), worker(indx).sc
NEXT
_PRINTSTRING (10, 380), "Press 'd' toggle thread slowdown. Press 's' to start/stop threads. Press 'ESC' to exit."
_LIMIT 60
_DISPLAY
LOOP
SUB resetWorker (id AS LONG)
worker(id).xsize = 100
worker(id).ysize = 100
worker(id).xstart = 0
worker(id).ystart = 0
worker(id).x = worker(id).xstart
worker(id).y = worker(id).ystart
worker(id).xsize = 100
worker(id).ysize = 100
worker(id).xdir = 1
worker(id).colour = _RGB32(RND * 255, RND * 255, RND * 255)
END SUB
SUB workerThread (id AS LONG)
DIM AS INTEGER dly
DO
lockThread id
IF worker(id).x + worker(id).xdir > worker(id).xstart + worker(id).xsize OR worker(id).x + worker(id).xdir < worker(id).xstart THEN
worker(id).xdir = -worker(id).xdir
IF worker(id).y + 1 > worker(id).ysize THEN
resetWorker id
ELSE
worker(id).y = worker(id).y + 1
END IF
ELSE
worker(id).x = worker(id).x + worker(id).xdir
END IF
worker(id).offset = worker(id).img.OFFSET + (worker(id).x * 4) + (worker(id).y * worker(id).xsize * 4)
_MEMPUT worker(id).img, worker(id).offset + 0, _BLUE32(worker(id).colour) AS _UNSIGNED _BYTE
_MEMPUT worker(id).img, worker(id).offset + 1, _GREEN32(worker(id).colour) AS _UNSIGNED _BYTE
_MEMPUT worker(id).img, worker(id).offset + 2, _RED32(worker(id).colour) AS _UNSIGNED _BYTE
_MEMPUT worker(id).img, worker(id).offset + 3, 255 AS _UNSIGNED _BYTE
IF NOT worker(id).dly THEN dly = 0: DO: dly = dly + 1: LOOP UNTIL dly < 0
unlockThread id
LOOP WHILE worker(id).command = 0
exitThread
END SUB
2D physics engine https://github.com/mechatronic3000/fzxNGN
Untitled Rouge-like https://github.com/mechatronic3000/Untitled-Rougelike
QB Pool https://github.com/mechatronic3000/QBPool
Untitled Rouge-like https://github.com/mechatronic3000/Untitled-Rougelike
QB Pool https://github.com/mechatronic3000/QBPool