Hello
Well, I got threads to work...somewhat...mostly...kinda. I've run it many, many times and I only get core dumps occasionally ;). Its obviously not as stable as I like, but It is merely a proof of concept. Its okay for testing and it has taught me a lot.
I'm using a linux machine so I'm using the pthread library, but I imagine the process would be similar to make it work in Windows, no idea about Mac. To keep it simple I kept all of the pthread stuff in the header. Functions are of course in the QB program.
If you would like to try it and you are on a Linux box then here is the source.
This is the header required it must be saved as "qbthread2.h" in your folder with the program.
#include "pthread.h"
typedef struct thread_data {
float result;
} thread_data;
float FUNC_THREAD0(int16*_FUNC_THREAD0_INTEGER_A);
float FUNC_THREAD1(int16*_FUNC_THREAD1_INTEGER_A);
float FUNC_THREAD2(int16*_FUNC_THREAD2_INTEGER_A);
static pthread_mutex_t mutex0;
static pthread_mutex_t mutex1;
static pthread_mutex_t mutex2;
void* RunThread0(void *arg){
pthread_mutex_lock(&mutex0);
thread_data *tdata=(thread_data *)arg;
tdata->result = FUNC_THREAD0((int16*)&a);
pthread_mutex_unlock(&mutex0);
pthread_exit(NULL);
}
void* RunThread1(void *arg){
pthread_mutex_lock(&mutex1);
thread_data *tdata=(thread_data *)arg;
tdata->result = FUNC_THREAD1((int16*)&a);
pthread_mutex_unlock(&mutex1);
pthread_exit(NULL);
}
void* RunThread2(void *arg){
pthread_mutex_lock(&mutex2);
thread_data *tdata=(thread_data *)arg;
tdata->result = FUNC_THREAD2((int16*)&a);
pthread_mutex_unlock(&mutex2);
pthread_exit(NULL);
}
pthread_t threads01;
pthread_t threads02;
pthread_t threads03;
thread_data tdata1;
thread_data tdata2;
thread_data tdata3;
tdata1.a = a;
tdata2.a = b;
tdata3.a = c;
int t1
= pthread_create
(&threads01
, NULL
, RunThread0
, (void
*)&tdata1
);
{
cout << "Error in thread creation: " << t1 << endl;
}
int t2
= pthread_create
(&threads02
, NULL
, RunThread1
, (void
*)&tdata2
);
{
cout << "Error in thread creation: " << t2 << endl;
}
int t3
= pthread_create
(&threads03
, NULL
, RunThread2
, (void
*)&tdata3
);
{
cout << "Error in thread creation: " << t3 << endl;
}
void* status1;
void* status2;
void* status3;
t1 = pthread_join(threads01, &status1);
{
cout << "Error in thread join: " << t1 << endl;
}
t2 = pthread_join(threads02, &status2);
{
cout << "Error in thread join: " << t2 << endl;
}
t3 = pthread_join(threads03, &status3);
{
cout << "Error in thread join: " << t3 << endl;
}
return tdata1.result
+ tdata2.result
+ tdata3.result;
}
{
pthread_t threads[3];
thread_data tdata[3];
tdata[0].a = a;
tdata[1].a = b;
tdata[2].a = c;
{
int t
= pthread_create
(&threads
[i
], NULL
, RunThread0
, (void
*)&tdata
[i
]);
{
cout << "Error in thread creation: " << t << endl;
}
}
{
void* status;
int t
= pthread_join
(threads
[i
], &status
);
{
cout << "Error in thread join: " << t << endl;
}
}
return tdata
[0].result
+ tdata
[1].result
+ tdata
[2].result;
}
Here is the QBasic portion. It can be saved as whatever you like.
' a,b,c are integers passed to the individual threads
' right now only a long value is returned
CONST cSUBITERATIONS
= 1000 CONST cFUNCTIONITERATIONS
= 20000
i = 0
PRINT "Invoke Three Different Functions --- Iteration:"; i
z = invokeThreadsMethodOne(cSUBITERATIONS, cSUBITERATIONS, cSUBITERATIONS)
PRINT "Threads returned:"; z
i = i + 1
PRINT "Press Space to continue..."
i = 0
PRINT "Invoke Same Function Three Times --- Iteration:"; i
z = invokeThreadsMethodTwo(cSUBITERATIONS, cSUBITERATIONS, cSUBITERATIONS)
PRINT "Threads returned:"; z
i = i + 1
PRINT "Press Space to continue..."
i = 0
PRINT "Just Call Functions Normally --- Iteration:"; i
z = thread0(cSUBITERATIONS) + thread1(cSUBITERATIONS) + thread2(cSUBITERATIONS)
PRINT "Functions returned:"; z
i = i + 1
'***********************************************************************************
' Threaded Functions
'***********************************************************************************
FOR i
= 1 TO a
* cFUNCTIONITERATIONS
o = o + 7
thread0 = o
FOR i
= 1 TO a
* cFUNCTIONITERATIONS
o = o + 7
thread1 = o
FOR i
= 1 TO a
* cFUNCTIONITERATIONS
o = o + 7
thread2 = o
In the program I tested a couple of different approaches to creating threads to see how it effects stability and speed and compared it to a baseline of just running the functions sequentially.
On my machine which is few years old and not very fast to begin with I got these results.
- Pthreads opens 3 threads of different functions that perform the same task - 41.03 seconds
- Pthreads opens 3 threads of a single function - 29.33 seconds
- Run the functions normally in sequence - 27.54 seconds
Needless to say the result were surprising. Unless there is some flaw in the way I implemented the threads or the test, it appears that running a single sequential thread outperforms three threads. I suspect that the overhead in creating the threads may play a part in it, or more likely my test is garbage. The attached pictures show my CPU utilzation during the tests.
The first method is unorthodox and occassionally returns the wrong result. Clearly a bad idea, but now I know for sure.
I might experiment with more threads to see if results change.