C++ Semaphore Confusion? - c++

So, I'm writing a sort of oscilloscope-esque program that reads the the serial port on the computer and performs an fft on this data to convert it to the frequency spectrum. I ran into an issue though with the layout of my program which is broken up into a SerialHandler class (utilizing boost::Asio), an FFTHandler class, and a main function. The SerialHandler class uses the boost::Asio`` async_read_some function to read from the port and raise an event called HandleOnPortReceive which then reads the data itself.
The issue was that I couldn't find a way to pass that data from the event handler, being raised by an io_service object on another thread, to the FFTHandler class, which is on yet another thread. I was recommended to use semaphores to solve my problem, but I have next to no knowledge on semaphore.h usage, so my implementation is now rather broken and doesn't do much of anything it's supposed to.
Here's some code if that makes it a little clearer:
using namespace Foo;
//main function
int main(void){
SerialHandler serialHandler;
FFTHandler fftHandler;
sem_t *qSem_ptr = &qSem;
sem_init(qSem_ptr, 1, 0);
//create separate threads for both the io_service and the AppendIn so that neither will block the user input statement following
serialHandler.StartConnection(tempInt, tempString); //these args are defined, but for brevity's sake, I ommitted the declaration
t2= new boost::thread(boost::bind(&FFTHandler::AppendIn, &fftHandler, q, qSem));
//allow the user to stop the program and avoid the problem of an infinite loop blocking the program
char inChar = getchar();
if (inChar) {...some logic to stop reading}
}
namespace Foo{
boost::thread *t1;
boost::thread *t2;
sem_t qSem;
std::queue<double> q;
boost::mutex mutex_;
class SerialHandler{
private:
char *rawBuffer; //array to hold incoming data
boost::asio::io_service ioService;
boost::asio::serial_port_ptr serialPort;
public:
void SerialHandler::StartConnection(int _baudRate, string _comPort){
//some functionality to open the port that is irrelevant to the question goes here
AsyncReadSome(); //starts the read loop
//create thread for io_service object and let function go out of scope
t1 = new boost::thread(boost::bind(&boost::asio::io_service::run, &ioService));
}
void SerialHandler::AsyncReadSome(){
//there's some other stuff here for error_catching, but this is the only important part
serialPort->async_read_some (
boost::asio::buffer(rawBuffer, SERIAL_PORT_READ_BUF_SIZE),
boost::bind(
&SerialHandler::HandlePortOnReceive,
this, boost::asio::placeholders::error,
boost::asio::placeholders::bytes_transferred, q));
}
void SerialHandler::HandlePortOnReceive(const boost::system::error_code& error, size_t bytes_transferred, std::queue<double>& q){
boost::mutex::scoped_lock lock(mutex_);
//more error checking goes here, but I've made sure they aren't returning and are not the issue
for (unsigned int i =0; i<bytes_transferred; i++){
unsigned char c = rawBuffer[i];
double d = (double) c; //loop through buffer and read
if (c==endOfLineChar){
} else //if not delimiting char, push into queue and post semaphore
{
q.push(d);
//cout << d << endl;
sem_post(&qSem);
cout << q.front() << endl;
cout << "size is: " << q.size() << endl;
}
}
//loop back on itself and start the next read
AsyncReadSome();
}
}
class FFTHandler{
private:
double *in; //array to hold inputs
fftw_complex *out; //holds outputs
int currentIndex;
bool filled;
const int N;
public:
void AppendIn(std::queue<double> &q, sem_t &qSem){
while(1){ //this is supposed to stop thread from exiting and going out of scope...it doesn't do that at all effectively...
cout << "test" << endl;
sem_wait(&_qSem); //wait for data...this is blocking but I don't know why
double d = _q.front();
_q.pop();
in[currentIndex]=d; //read queue, pop, then append in array
currentIndex++;
if (currentIndex == N){ //run FFT if full and reset index
currentIndex = N-overlap-1;
filled = true;
RunFFT();
}
}
}
}
}
That debug line in FFTHandler::AppendIn(..) is indeed firing, so the thread is being created, but it's immediateley going out of scope it seems and destructing the thread, because it seems I've set up the while to respond incorrectly to the semaphore.
TLDR: That was a long explanation to simply say, "I don't understand semaphores but need to somehow implement them. I tried, failed, so now I'm coming here to hopefully receive help on this code from somebody more knowledgeable than me.
UPDATE: So after playing around with some debug statements, it seems that the issue is that the while(1){...} statement is indeed firing, but, the sem_wait(&_qSem); is causing it to block. For whatever reason it is waiting indefinitely and despite the fact that the semaphore is being posted, it continues to wait and never progress beyond that line.

Since you're already using boost::mutex and its scoped lock type, I suggest you use boost::condition_variable instead of a POSIX semaphore. Otherwise you're mixing C++11-style synchronisation with POSIX synchronisation.
You lock the mutex when adding to the queue, but I don't see anything locking the mutex to read from the queue. It also looks like you're looping back to call AsyncReadSome while the mutex is still locked.
Pick a single form of synchronisation, and then use it correctly.

The initial value of the semaphore is 0 which is valid for this case. So it needs a sem_post for FFTHandler::AppendIn() to be unblocked. But I dont see the code that invokes SerialHandler::AsyncReadSome() for the first time for the serial port to be read and the push to happen into the queue. If you fix that part of the code, I think sem_post would happen and the FFTHandler thread would run. As the first step you can have debug prints one after the sem_wait and one inside AsyncReadSome() function, and my guess is that both wont get executed.
So, essentially you would want to ensure that 'reading' gets initiated and is kept alive as part of the main thread or a different thread.

Related

C++ thread writes continuously and read at unknown time

I am trying to get the following scenario to work, but have not been successful so far.
I have 2 threads, a worker (that writes) and a reader.
The worker continuously modifies the values of a class "someClassToModify".
The Reader makes a read access every x seconds (unknown) and reads the current state of the class someClassToModify.
How do I make sure that the Reader reads someClassToModify immediately, without delay, when it "wants" to and the Worker continues immediately afterwards ?
What is important here is that the reader always gets immediate access when it needs it to take a "snapshot" of someClassToModify .
At the moment, the Writer seems to be always "faster", and sometimes several more "Writes" are made before it is the reader's turn. That is, the reader then does not get the actual value that he wanted.
Example:
Work
Work
Work
Work
Read
Work
Work
Read
Work
Work
Work
Work
Read
....
SomeClass someClassToModify; //Class to modify and read
std::thread Worker([this] {
while(true) {
// work work work (write)
// modify someClassToModify
}
}).detach();
std::thread Reader([this] {
while(true) {
//at an unknown time (random) read value from someClassToModify
}
}).detach();
thanks for your help here
So, first of all you should note that threads switch at random. That means that worker can do something multiple times before even a single reader gets chance to do anything.
Second thing is that reader can access function and for example come to 3rd line and then the context switch happens. You want to avoid that.
The way to avoid that is by using lock or semaphore.
That means that your class someClassToModify method should disable context switch while reading. It doesnt need to have anything special for explicit switch as it will sleep afterwards for X seconds and during that time the modifier will work.
You should check std::lock.
Basically you would want something like this, wrap this inside your class
#include<iostream>
#include<thread>
#include<mutex>
#include <chrono>
int i = 0;
int x = 1000;
//this is mutex for waiting
std::mutex myLock;
void read() {
while (true) {
//you lock the function, so it will not change context
myLock.lock();
std::cout << i << std::endl;
std::cout << "reader" << std::endl;
//once it is finish you can unlock it
myLock.unlock();
//wait for x miliseconds
std::this_thread::sleep_for(std::chrono::milliseconds(x));
}
}
void write() {
while (true) {
//writer also has lock so you dont end up with bad values on i
myLock.lock();
i++;
std::cout << "writer" << std::endl;
myLock.unlock();
}
}
int main() {
std::thread th1(read);
std::thread th2(write);
th1.join();
th2.join();
return 0;
}

Reusing thread in loop c++

I need to parallelize some tasks in a C++ program and am completely new to parallel programming. I've made some progress through internet searches so far, but am a bit stuck now. I'd like to reuse some threads in a loop, but clearly don't know how to do what I'm trying for.
I am acquiring data from two ADC cards on the computer (acquired in parallel), then I need to perform some operations on the collected data (processed in parallel) while collecting the next batch of data. Here is some pseudocode to illustrate
//Acquire some data, wait for all the data to be acquired before proceeding
std::thread acq1(AcquireData, boardHandle1, memoryAddress1a);
std::thread acq2(AcquireData, boardHandle2, memoryAddress2a);
acq1.join();
acq2.join();
while(user doesn't interrupt)
{
//Process first batch of data while acquiring new data
std::thread proc1(ProcessData,memoryAddress1a);
std::thread proc2(ProcessData,memoryAddress2a);
acq1(AcquireData, boardHandle1, memoryAddress1b);
acq2(AcquireData, boardHandle2, memoryAddress2b);
acq1.join();
acq2.join();
proc1.join();
proc2.join();
/*Proceed in this manner, alternating which memory address
is written to and being processed until the user interrupts the program.*/
}
That's the main gist of it. The next run of the loop would write to the "a" memory addresses while processing the "b" data and continue to alternate (I can get the code to do that, just took it out to prevent cluttering up the problem).
Anyway, the problem (as I'm sure some people can already tell) is that the second time I try to use acq1 and acq2, the compiler (VS2012) says "IntelliSense: call of an object of a class type without appropriate operator() or conversion functions to pointer-to-function type". Likewise, if I put std::thread in front of acq1 and acq2 again, it says " error C2374: 'acq1' : redefinition; multiple initialization".
So the question is, can I reassign threads to a new task when they have completed their previous task? I always wait for the previous use of the thread to end before calling it again, but I don't know how to reassign the thread, and since it's in a loop, I can't make a new thread each time (or if I could, that seems wasteful and unnecessary, but I could be mistaken).
Thanks in advance
The easiest way is to use a waitable queue of std::function objects. Like this:
#include <iostream>
#include <thread>
#include <mutex>
#include <condition_variable>
#include <queue>
#include <functional>
#include <chrono>
class ThreadPool
{
public:
ThreadPool (int threads) : shutdown_ (false)
{
// Create the specified number of threads
threads_.reserve (threads);
for (int i = 0; i < threads; ++i)
threads_.emplace_back (std::bind (&ThreadPool::threadEntry, this, i));
}
~ThreadPool ()
{
{
// Unblock any threads and tell them to stop
std::unique_lock <std::mutex> l (lock_);
shutdown_ = true;
condVar_.notify_all();
}
// Wait for all threads to stop
std::cerr << "Joining threads" << std::endl;
for (auto& thread : threads_)
thread.join();
}
void doJob (std::function <void (void)> func)
{
// Place a job on the queu and unblock a thread
std::unique_lock <std::mutex> l (lock_);
jobs_.emplace (std::move (func));
condVar_.notify_one();
}
protected:
void threadEntry (int i)
{
std::function <void (void)> job;
while (1)
{
{
std::unique_lock <std::mutex> l (lock_);
while (! shutdown_ && jobs_.empty())
condVar_.wait (l);
if (jobs_.empty ())
{
// No jobs to do and we are shutting down
std::cerr << "Thread " << i << " terminates" << std::endl;
return;
}
std::cerr << "Thread " << i << " does a job" << std::endl;
job = std::move (jobs_.front ());
jobs_.pop();
}
// Do the job without holding any locks
job ();
}
}
std::mutex lock_;
std::condition_variable condVar_;
bool shutdown_;
std::queue <std::function <void (void)>> jobs_;
std::vector <std::thread> threads_;
};
void silly (int n)
{
// A silly job for demonstration purposes
std::cerr << "Sleeping for " << n << " seconds" << std::endl;
std::this_thread::sleep_for (std::chrono::seconds (n));
}
int main()
{
// Create two threads
ThreadPool p (2);
// Assign them 4 jobs
p.doJob (std::bind (silly, 1));
p.doJob (std::bind (silly, 2));
p.doJob (std::bind (silly, 3));
p.doJob (std::bind (silly, 4));
}
The std::thread class is designed to execute exactly one task (the one you give it in the constructor) and then end. If you want to do more work, you'll need a new thread. As of C++11, that's all we have. Thread pools didn't make it into the standard. (I'm uncertain what C++14 has to say about them.)
Fortunately, you can easily implement the required logic yourself. Here is the large-scale picture:
Start n worker threads that all do the following:
Repeat while there is more work to do:
Grab the next task t (possibly waiting until one becomes ready).
Process t.
Keep inserting new tasks in the processing queue.
Tell the worker threads that there is nothing more to do.
Wait for the worker threads to finish.
The most difficult part here (which is still fairly easy) is properly designing the work queue. Usually, a synchronized linked list (from the STL) will do for this. Synchronized means that any thread that wishes to manipulate the queue must only do so after it has acquired a std::mutex so to avoid race conditions. If a worker thread finds the list empty, it has to wait until there is some work again. You can use a std::condition_variable for this. Each time a new task is inserted into the queue, the inserting thread notifies a thread that waits on the condition variable and will therefore stop blocking and eventually start processing the new task.
The second not-so-trivial part is how to signal to the worker threads that there is no more work to do. Clearly, you can set some global flag but if a worker is blocked waiting at the queue, it won't realize any time soon. One solution could be to notify_all() threads and have them check the flag each time they are notified. Another option is to insert some distinct “toxic” item into the queue. If a worker encounters this item, it quits itself.
Representing a queue of tasks is straight-forward using your self-defined task objects or simply lambdas.
All of the above are C++11 features. If you are stuck with an earlier version, you'll need to resort to third-party libraries that provide multi-threading for your particular platform.
While none of this is rocket science, it is still easy to get wrong the first time. And unfortunately, concurrency-related bugs are among the most difficult to debug. Starting by spending a few hours reading through the relevant sections of a good book or working through a tutorial can quickly pay off.
This
std::thread acq1(...)
is the call of an constructor. constructing a new object called acq1
This
acq1(...)
is the application of the () operator on the existing object aqc1. If there isn't such a operator defined for std::thread the compiler complains.
As far as I know you may not reused std::threads. You construct and start them. Join with them and throw them away,
Well, it depends if you consider moving a reassigning or not. You can move a thread but not make a copy of it.
Below code will create new pair of threads each iteration and move them in place of old threads. I imagine this should work, because new thread objects will be temporaries.
while(user doesn't interrupt)
{
//Process first batch of data while acquiring new data
std::thread proc1(ProcessData,memoryAddress1a);
std::thread proc2(ProcessData,memoryAddress2a);
acq1 = std::thread(AcquireData, boardHandle1, memoryAddress1b);
acq2 = std::thread(AcquireData, boardHandle2, memoryAddress2b);
acq1.join();
acq2.join();
proc1.join();
proc2.join();
/*Proceed in this manner, alternating which memory address
is written to and being processed until the user interrupts the program.*/
}
What's going on is, the object actually does not end it's lifetime at the end of the iteration, because it is declared in the outer scope in regard to the loop. But a new object gets created each time and move takes place. I don't see what can be spared (I might be stupid), so I imagine this it's exactly the same as declaring acqs inside the loop and simply reusing the symbol. All in all ... yea, it's about how you classify a create temporary and move.
Also, this clearly starts a new thread each loop (of course ending the previously assigned thread), it doesn't make a thread wait for new data and magically feed it to the processing pipe. You would need to implement it a differently like. E.g: Worker threads pool and communication over queues.
References: operator=, (ctor).
I think the errors you get are self-explanatory, so I'll skip explaining them.
I think you need a much more simpler answer for running a set of threads more than once, this is the best solution:
do{
std::vector<std::thread> thread_vector;
for (int i=0;i<nworkers;i++)
{
thread_vector.push_back(std::thread(yourFunction,Parameter1,Parameter2, ...));
}
for(std::thread& it: thread_vector)
{
it.join();
}
q++;
} while(q<NTIMES);
You also could make your own Thread class and call its run method like:
class MyThread
{
public:
void run(std::function<void()> func) {
thread_ = std::thread(func);
}
void join() {
if(thread_.joinable())
thread_.join();
}
private:
std::thread thread_;
};
// Application code...
MyThread myThread;
myThread.run(AcquireData);

multithreading thread switching issue

I have a producer and consumer thread that are being created from main. They perform correctly well, except for the cout statement
class myclass{
int x;
// stuff
}
void foo1(myclass* ob){
setX(ob->x);
// stuff
}
void foo2(myclass* ob){
cout << ob->x << endl; // ONLY THIS DOESN'T EXECUTE
ob->getX();
// stuff
}
int main(){
myclass* ob = new myclass();
boost::thread producer_thread(boost::bind(foo1, ob));
boost::thread consumer_thread(boost::bind(foo2, ob));
// stuff
producer_thread.join();
consumer_thread.join();
}
Everything works fine (including showX that displays x, except for the cout. What's wrong?
Your threads are sharing the object without actually any lock on it. producer is not exiting before consumer started accessing the object.
Using producer_thread.join() before boost::thread consumer_thread(boost::bind(foo2, ob)) should resolve this, which is not the best fix. Using mutex locks will be ideal.
Adding to the previous answer, you can also use a state variable or condition variable to ensure that your object is not getting written upon / processed by a thread when some other thread is working on it. In other words, you can have a state variable whose value is changed by each function to a unique number upon completion and each function will start operating when the state variable is assumes the value that the previous function is supposed to set it to.

when to use mutex

Here is the thing: there is a float array float bucket[5] and 2 threads, say thread1 and thread2.
Thread1 is in charge of tanking up the bucket, assigning each element in bucket a random number. When the bucket is tanked up, thread2 will access bucket and read its elements.
Here is how I do the job:
float bucket[5];
pthread_mutex_t mu = PTHREAD_MUTEX_INITIALIZER;
pthread_t thread1, thread2;
void* thread_1_proc(void*); //thread1's startup routine, tank up the bucket
void* thread_2_proc(void*); //thread2's startup routine, read the bucket
int main()
{
pthread_create(&thread1, NULL, thread_1_proc, NULL);
pthread_create(&thread2, NULL, thread_2_proc, NULL);
pthread_join(thread1);
pthread_join(thread2);
}
Below is my implementation for thread_x_proc:
void* thread_1_proc(void*)
{
while(1) { //make it work forever
pthread_mutex_lock(&mu); //lock the mutex, right?
cout << "tanking\n";
for(int i=0; i<5; i++)
bucket[i] = rand(); //actually, rand() returns int, doesn't matter
pthread_mutex_unlock(&mu); //bucket tanked, unlock the mutex, right?
//sleep(1); /* this line is commented */
}
}
void* thread_2_proc(void*)
{
while(1) {
pthread_mutex_lock(&mu);
cout << "reading\n";
for(int i=0; i<5; i++)
cout << bucket[i] << " "; //read each element in the bucket
pthread_mutex_unlock(&mu); //reading done, unlock the mutex, right?
//sleep(1); /* this line is commented */
}
}
Question
Is my implementation right? Cuz the output is not as what I expected.
...
reading
5.09434e+08 6.58441e+08 1.2288e+08 8.16198e+07 4.66482e+07 7.08736e+08 1.33455e+09
reading
5.09434e+08 6.58441e+08 1.2288e+08 8.16198e+07 4.66482e+07 7.08736e+08 1.33455e+09
reading
5.09434e+08 6.58441e+08 1.2288e+08 8.16198e+07 4.66482e+07 7.08736e+08 1.33455e+09
reading
tanking
tanking
tanking
tanking
...
But if I uncomment the sleep(1); in each thread_x_proc function, the output is right, tanking and reading follow each other, like this:
...
tanking
reading
1.80429e+09 8.46931e+08 1.68169e+09 1.71464e+09 1.95775e+09 4.24238e+08 7.19885e+08
tanking
reading
1.64976e+09 5.96517e+08 1.18964e+09 1.0252e+09 1.35049e+09 7.83369e+08 1.10252e+09
tanking
reading
2.0449e+09 1.96751e+09 1.36518e+09 1.54038e+09 3.04089e+08 1.30346e+09 3.50052e+07
...
Why? Should I use sleep() when using mutex?
Your code is technically correct, but it does not make a lot of sense, and it does not do what you assume.
What your code does is, it updates a section of data atomically, and reads from that section, atomically. However, you don't know in which order this happens, nor how often the data is written to before being read (or if at all!).
What you probably wanted is generate exactly one sequence of numbers in one thread every time and read exactly one new sequence each time in the other thread. For this, you would use either have to use an additional semaphore or better a single-producer-single-consumer queue.
In general the answer to "when should I use a mutex" is "never, if you can help it". Threads should send messages, not share state. This makes a mutex most of the time unnecessary, and offers parallelism (which is the main incentive for using threads in the first place).
The mutex makes your threads run lockstep, so you could as well just run in a single thread.
There is no implied order in which threads will get to run. This means you shall not expect any order. What's more it is possible to get on thread running over and over without letting the other to run. This is implementation specific and should be assumed random.
The case you presented falls much rather for a semaphor which is "posted" with each element added.
However if it has always to be like:
write 5 elements
read 5 elements
you should have two mutexes:
one that blocks producer until the consumer finished
one that blocks consumer until the producer finished
So the code should look something like that:
Producer:
while(true){
lock( &write_mutex )
[insert data]
unlock( &read_mutex )
}
Consumer:
while(true){
lock( &read_mutex )
[insert data]
unlock( &write_mutex )
}
Initially write_mutex should be unlocked and read_mutex locked.
As I said your code seems to be a better case for semaphores or maybe condition variables.
Mutexes are not meant for cases such as this (which doesn't mean you can't use them, it just means there are more handy tools to solve that problem).
You have no right to assume that just because you want your threads to run in a particular order, the implementation will figure out what you want and actually run them in that order.
Why shouldn't thread2 run before thread1? And why shouldn't each thread complete its loop several times before the other thread gets a chance to run up to the line where it acquires the mutex?
If you want execution to switch between two threads in a predictable way, then you need to use a semaphore, condition variable, or other mechanism for messaging between the two threads. sleep appears to result in the order you want on this occasion, but even with the sleep you haven't done enough to guarantee that they will alternate. And I have no idea why the sleep makes a difference to which thread gets to run first -- is that consistent across several runs?
If you have two functions that should execute sequentially, i.e. F1 should finish before F2 starts, then you shouldn't be using two threads. Run F2 on the same thread as F1, after F1 returns.
Without threads, you won't need the mutex either.
It isn't really the issue here.
The sleep only lets the 'other' thread access the mutex lock (by chance, it is waiting for the lock so Probably it will have the mutex), there is no way you can be sure the first thread won't re-lock the mutex though and let the other thread access it.
Mutex is for protecting data so two threads don't :
a) write simultaneously
b) one is writing when another is reading
It is not for making threads work in a certain order (if you want that functionality, ditch the threaded approach or use a flag to tell that the 'tank' is full for example).
By now, it should be clear, from the other answers, what are the mistakes in the original code. So, let's try to improve it:
/* A flag that indicates whose turn it is. */
char tanked = 0;
void* thread_1_proc(void*)
{
while(1) { //make it work forever
pthread_mutex_lock(&mu); //lock the mutex
if(!tanked) { // is it my turn?
cout << "tanking\n";
for(int i=0; i<5; i++)
bucket[i] = rand(); //actually, rand() returns int, doesn't matter
tanked = 1;
}
pthread_mutex_unlock(&mu); // unlock the mutex
}
}
void* thread_2_proc(void*)
{
while(1) {
pthread_mutex_lock(&mu);
if(tanked) { // is it my turn?
cout << "reading\n";
for(int i=0; i<5; i++)
cout << bucket[i] << " "; //read each element in the bucket
tanked = 0;
}
pthread_mutex_unlock(&mu); // unlock the mutex
}
}
The code above should work as expected. However, as others have pointed out, the result would be better accomplished with one of these two other options:
Sequentially. Since the producer and the consumer must alternate, you don't need two threads. One loop that tanks and then reads would be enough. This solution would also avoid the busy waiting that happens in the code above.
Using semaphores. This would be the solution if the producer was able to run several times in a row, accumulating elements in a bucket (not the case in the original code, though).
http://en.wikipedia.org/wiki/Producer-consumer_problem#Using_semaphores

Pthread Passing Function to Pool

I am working on creating a threadpool from scratch as part of an assignment and am able to create the thread pool and then pass each created thread a function that constantly loops. My question is how can I accept the input and pass it to an already executing pthread. After figuring this out I will add mutexes to lock the function to a specific thread, but I am unable to get to that part.
class ThreadPool{
public:
ThreadPool(size_t threadCount);
int dispatch_thread(void *(dispatch_function(void *)), void *arg);
bool thread_avail();
int numThreads;
pthread_t * thread;
pthread_mutex_t * mutexes;
};
int ThreadPool::dispatch_thread(void *(dispatch_function(void *)), void *arg){
flag = 1;
//This is where I would like to pass the function the running pthread
}
void *BusyWork(void *t)
{
while(true){
//This is where I would like to run the passed function from each thread
//I can run the passed function by itself, but need to pass it to the threadpool
}
}
ThreadPool::ThreadPool(size_t threadCount){
pthread_t thread[threadCount];
for(t=0; t<threadCount; t++) {
//printf("Main: creating thread %ld\n", t);
rc = pthread_create(&thread[t], NULL, BusyWork, (void *)t);
}
}
void *test_fn(void *par)
{
cout << "in test_fn " << *(int *)par << endl;
}
int main (){
ThreadPool th(3);
int max = 100;
for (int i = 0; i < 20; i++) {
max = 100 * i;
th.dispatch_thread(test_fn, (void *)&max);
sleep(1);
}
}
The best pattern that I can think of is to use some sort of queue to pass messages to the thread-pool. These messages may contain functions to be run as well as some control messages for shutting down the thread-pool. As you already have guessed, the queue will have to be thread safe.
A simple approach for the queue is to use a fixed size array which you turn into a circular buffer. The array will have a Mutex to lock it when accessing the array and a Condition Variable to awaken the thread-pool thread.
When putting an item on the queue, we lock the mutex, add to the queue and then signal the thread-pool with the Condition Variable.
Each running thread in the in the thread pool will start life by locking the mutex and waiting on the condition varaible (which automaticall unlocks the Mutex). When awoken it will remove the item from the queue, and then unlock the mutex. It is now free do its stuff. When finished it goes to sleep until re-signaled.
As general advice, avoid sharing memory between threads because this either leads to race conditions (if access is not protected) or leads to interlocking (if access is locked). Also avoid locking a mutex when performing any long running operation such as calling new (malloc), delete (free) or any system calls.