05-27-2024, 12:58 AM
Hello all,
I've been revisiting my earlier attempt at threading in QB64pe. You can look at the old thread at https://qb64forum.alephc.xyz/index.php?topic=3865.0 Thanks to guys that responded to that thread and helped me.
I'm happy to say I made a bit of progress. I managed to get two separate free running threads to run concurrent with my main QB64 program. They don't do much, but they show its possible.
In order to get it working I had to cheat and use a c header file to make a wrapper for pthreads. This makes the declarations easier.
The test program draws lines in one thread and circles in another thread. You start and stop the threads by pressing '1' and '2' and 'ESC' quits.
My goal, is to get my 2d physics engine to reside in a separate thread and have it free running computing collisions and motion while the main thread handles I/O and other logic.
I'm using QB64pe 3.11.0. I tested this on Linux Mint, MacOS and Windows 10. On windows I had to add '-pthread' to compiler settings and '--static' to the linker settings.
To get this running on your computer, copy the header to your favorite text editor and save the file under 'pthreadGFXTest.h' Then copy the source to the same directory as the header and make sure your compiler and linker settings are correct. I'm not sure if its necessary, but I save my EXE to the source folder.
Beware that if you decide try playing around with the code, that it could crash in some wild ways. Error messages will not make sense, and it might run a bit and lockup for unknown reasons. QB64pe is not meant to be run like this, so there will not be much help if you try.
I've been revisiting my earlier attempt at threading in QB64pe. You can look at the old thread at https://qb64forum.alephc.xyz/index.php?topic=3865.0 Thanks to guys that responded to that thread and helped me.
I'm happy to say I made a bit of progress. I managed to get two separate free running threads to run concurrent with my main QB64 program. They don't do much, but they show its possible.
In order to get it working I had to cheat and use a c header file to make a wrapper for pthreads. This makes the declarations easier.
Code: (Select All)
// pthreadGFXTest.h
// Threading Header
#include "pthread.h"
// Only needed for the SIGTERM Constant
#include <signal.h>
// Initialize Threads
pthread_t thread0;
pthread_t thread1;
// Easy way to determine if a thread is running
bool threadRunning0 = false;
bool threadRunning1 = false;
// Setup Mutexes for each of the threads.
static pthread_mutex_t mutex0;
static pthread_mutex_t mutex1;
// 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_LINES();
void SUB_CIRCLES();
// wrap the subs so that you can easily get the void* for pthread
void* RunLines(void *arg){
SUB_LINES();
}
void* RunCircles(void *arg){
SUB_CIRCLES();
}
// These are the commands that are accessed by you program
void invokeLines(){
if (!threadRunning0) {
int iret = pthread_create( &thread0, NULL, RunLines, NULL);
pthread_mutex_init(&mutex0, NULL);
threadRunning0 = true;
}
}
void invokeCircles(){
if (!threadRunning1) {
int iret = pthread_create( &thread1, NULL, RunCircles, NULL);
pthread_mutex_init(&mutex1, NULL);
threadRunning1 = true;
}
}
void joinThread0(){
pthread_join(thread0,NULL);
threadRunning0 = false;
}
void joinThread1(){
pthread_join(thread1,NULL);
threadRunning1 = false;
}
void exitThread(){
pthread_exit(NULL);
}
void killThread0(){
if (threadRunning0) {
int iret = pthread_kill(thread0, SIGTERM);
}
}
void killThread1(){
if (threadRunning1) {
int iret = pthread_kill(thread1, SIGTERM);
}
}
void lockThread0(){
pthread_mutex_lock(&mutex0);
}
void unlockThread0(){
pthread_mutex_unlock(&mutex0);
}
void lockThread1(){
pthread_mutex_lock(&mutex1);
}
void unlockThread1(){
pthread_mutex_unlock(&mutex1);
}
The test program draws lines in one thread and circles in another thread. You start and stop the threads by pressing '1' and '2' and 'ESC' quits.
Code: (Select All)
'***********************************************************************************
' Proof of concept threading in QB64pe.
' by justsomeguy
'***********************************************************************************
' Thread Library Declaration
DECLARE LIBRARY "./pthreadGFXTest"
SUB invokeLines ' start Lines thread
SUB invokeCircles ' start Circles thread
SUB joinThread0 ' wait til thread is finished
SUB joinThread1 ' wait til thread is finished
SUB exitThread ' must be called as thread exits
SUB killThread0 ' kill the thread
SUB killThread1 ' kill the thread
SUB lockThread0 ' mutex lock
SUB unlockThread0 ' mutex unlock
SUB lockThread1 ' mutex lock
SUB unlockThread1 ' mutex unlock
END DECLARE
' Global variables
DIM SHARED AS INTEGER q0, q1 ' quit signals
DIM AS STRING ky
' Setup screen
_TITLE "Thread test"
SCREEN _NEWIMAGE(1024, 768, 32)
_FONT 8
CLS
' Fire up freerunning threads
invokeCircles
invokeLines
' Campout in an infinite loop
DO
ky = INKEY$
LOCATE 1, 1
PRINT "Lines are drawn on one thread, Circles are drawn in a second thread."
PRINT "Press '1' to toggle the Line drawing thread. "
PRINT "Press '2' to toggle the Circle drawing thread."
PRINT "Press 'ESC' to exit."
IF ky = "1" THEN
q0 = NOT q0
IF q0 THEN
joinThread0
ELSE
invokeLines
END IF
END IF
IF ky = "2" THEN
q1 = NOT q1
IF q1 THEN
joinThread1
ELSE
invokeCircles
END IF
END IF
' Quit the whole program
IF ky = CHR$(27) THEN q0 = -1: q1 = -1: joinThread0: joinThread1: SYSTEM
LOOP
'***********************************************************************************
' Threaded
'***********************************************************************************
SUB lines ()
' Free running loop
DO
' lock a mutex, just to be safe
lockThread0
' Do something
LINE (RND * _WIDTH, RND * _HEIGHT)-(RND * _WIDTH, RND * _HEIGHT), _RGB32(RND * 255, RND * 255, RND * 255)
' unlock mutex
unlockThread0
' do I need to jump out?
LOOP UNTIL q0 = -1
' Must call exitThread when leaving, so that joinThread works.
exitThread
END SUB
SUB circles ()
' Free running loop
DO
' lock a mutex, just to be safe
lockThread1
' Do something
CIRCLE (RND * _WIDTH, RND * _HEIGHT), RND * 50, _RGB32(RND * 255, RND * 255, RND * 255)
' unlock mutex
unlockThread1
' do I need to jump out?
LOOP UNTIL q1 = -1
' Must call exitThread when leaving, so that joinThread works.
exitThread
END SUB
My goal, is to get my 2d physics engine to reside in a separate thread and have it free running computing collisions and motion while the main thread handles I/O and other logic.
I'm using QB64pe 3.11.0. I tested this on Linux Mint, MacOS and Windows 10. On windows I had to add '-pthread' to compiler settings and '--static' to the linker settings.
To get this running on your computer, copy the header to your favorite text editor and save the file under 'pthreadGFXTest.h' Then copy the source to the same directory as the header and make sure your compiler and linker settings are correct. I'm not sure if its necessary, but I save my EXE to the source folder.
Beware that if you decide try playing around with the code, that it could crash in some wild ways. Error messages will not make sense, and it might run a bit and lockup for unknown reasons. QB64pe is not meant to be run like this, so there will not be much help if you try.
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