What does a critical section have to do with counting semaphores? - concurrency

Some people say that you should use mutexes to protect shared resources (i.e. critical sections), while semaphores should be used for signaling and not vice versa. So, as far as I understand, semaphores have nothing to do with critical sections.
However many other articles, including Wikipedia state that semaphores are used to solve critical section problems. Is it actually more correct to say that binary semaphores solve critical section problems since they basically act like mutexes, while counting semaphores are a different thing and don't belong to the "resource protectors" category?

Counting semaphores can be used for resource protection, but they're typically used for different resources in different ways from a mutex semaphore.
A typical example would be a queue. For a dynamically sized queue, you have a counted semaphore to track how many items are currently in the queue. Consumers wait on that semaphore to tell them when they can read an item from the queue.
For a fixed-size queue, you add a second counted semaphore tracking the amount of empty space in the queue. Writers wait on it to determine when they're allowed to push an item to the queue.
You do often use a mutex semaphore in conjunction with those to assure that only a single thread modifies the queue itself at any given time.
For example, here's some code for a fixed-size queue using Win32 counted semaphores (and a mutex):
#ifndef QUEUE_H_INCLUDED
#define QUEUE_H_INCLUDED
#include <windows.h>
template<class T, unsigned max = 256>
class queue {
HANDLE space_avail; // at least one slot empty
HANDLE data_avail; // at least one slot full
CRITICAL_SECTION mutex; // protect buffer, in_pos, out_pos
T buffer[max];
long in_pos, out_pos;
public:
queue() : in_pos(0), out_pos(0) {
space_avail = CreateSemaphore(NULL, max, max, NULL);
data_avail = CreateSemaphore(NULL, 0, max, NULL);
InitializeCriticalSection(&mutex);
}
void push(T data) {
WaitForSingleObject(space_avail, INFINITE);
EnterCriticalSection(&mutex);
buffer[in_pos] = data;
in_pos = (in_pos + 1) % max;
LeaveCriticalSection(&mutex);
ReleaseSemaphore(data_avail, 1, NULL);
}
T pop() {
WaitForSingleObject(data_avail,INFINITE);
EnterCriticalSection(&mutex);
T retval = buffer[out_pos];
out_pos = (out_pos + 1) % max;
LeaveCriticalSection(&mutex);
ReleaseSemaphore(space_avail, 1, NULL);
return retval;
}
~queue() {
DeleteCriticalSection(&mutex);
CloseHandle(data_avail);
CloseHandle(space_avail);
}
};
#endif

Related

Producer-consumer based multi-threading for image processing

UPDATE: I have provided the reason of problem and its solution in my answer below.
I want to implement multi-threading which is based upon Producer-consumer approach for an image processing task. For my case, the Producer thread should grabs the images and put them into a container whereas the consumer thread should extract the images from the Container thread. I think that I should use queue for the implementation of container.
I want to use the following code as suggested in this SO answer. But I have become quite confused with the implementation of container and putting the incoming image into it in the Producer thread.
PROBLEM: The image displayed by the first consumer thread does not contain the full data. And, the second consumer thread never displays any image. May be, there is some race situation or lock situation due to which the second thread is not able to access the data of queue at all. I have already tried to use Mutex.
#include <vector>
#include <thread>
#include <memory>
#include <queue>
#include <opencv2/highgui.hpp>
#include <opencv2/core.hpp>
#include <opencv2/imgproc.hpp>
Mutex mu;
struct ThreadSafeContainer
{
queue<unsigned char*> safeContainer;
};
struct Producer
{
Producer(std::shared_ptr<ThreadSafeContainer> c) : container(c)
{
}
void run()
{
while(true)
{
// grab image from camera
// store image in container
Mat image(400, 400, CV_8UC3, Scalar(10, 100,180) );
unsigned char *pt_src = image.data;
mu.lock();
container->safeContainer.push(pt_src);
mu.unlock();
}
}
std::shared_ptr<ThreadSafeContainer> container;
};
struct Consumer
{
Consumer(std::shared_ptr<ThreadSafeContainer> c) : container(c)
{
}
~Consumer()
{
}
void run()
{
while(true)
{
// read next image from container
mu.lock();
if (!container->safeContainer.empty())
{
unsigned char *ptr_consumer_Image;
ptr_consumer_Image = container->safeContainer.front(); //The front of the queue contain the pointer to the image data
container->safeContainer.pop();
Mat image(400, 400, CV_8UC3);
image.data = ptr_consumer_Image;
imshow("consumer image", image);
waitKey(33);
}
mu.unlock();
}
}
std::shared_ptr<ThreadSafeContainer> container;
};
int main()
{
//Pointer object to the class containing a "container" which will help "Producer" and "Consumer" to put and take images
auto ptrObject_container = make_shared<ThreadSafeContainer>();
//Pointer object to the Producer...intialize the "container" variable of "Struct Producer" with the above created common "container"
auto ptrObject_producer = make_shared<Producer>(ptrObject_container);
//FIRST Pointer object to the Consumer...intialize the "container" variable of "Struct Consumer" with the above created common "container"
auto first_ptrObject_consumer = make_shared<Consumer>(ptrObject_container);
//SECOND Pointer object to the Consumer...intialize the "container" variable of "Struct Consumer" with the above created common "container"
auto second_ptrObject_consumer = make_shared<Consumer>(ptrObject_container);
//RUN producer thread
thread producerThread(&Producer::run, ptrObject_producer);
//RUN first thread of Consumer
thread first_consumerThread(&Consumer::run, first_ptrObject_consumer);
//RUN second thread of Consumer
thread second_consumerThread(&Consumer::run, second_ptrObject_consumer);
//JOIN all threads
producerThread.join();
first_consumerThread.join();
second_consumerThread.join();
return 0;
}
I don't see an actual question in your original question, so I'll give you the reference material I used to implement producer-consumer in my college course.
http://cs360.byu.edu/static/lectures/winter-2014/semaphores.pdf
Slides 13 and 17 give good examples of producer-consumer
I made use of this in the lab which I have posted on my github here:
https://github.com/qzcx/Internet_Programming/tree/master/ThreadedMessageServer
If you look in my server.cc you can see my implementation of the producer-consumer pattern.
Remember that using this pattern that you can't switch the order of the wait statements or else you can end up in deadlock.
Hope this is helpful.
EDIT:
Okay, so here is a summary of the consumer-producer pattern in my code linked above. The idea behind the producer consumer is to have a thread safe way of passing tasks from a "producer" thread to "consumer" worker threads. In the case of my example, the work to be done is to handle client requests. The producer thread (.serve()) monitors the incoming socket and passes the connection to consumer threads (.handle()) to handle the actual request as they come in. All of the code for this pattern is found in the server.cc file (with some declarations/imports in server.h).
For the sake of being brief, I am leaving out some detail. Be sure to go through each line and understand what is going on. Look up the library functions I am using and what the parameters mean. I'm giving you a lot of help here, but there is still plenty of work for you to do to gain a full understanding.
PRODUCER:
Like I mentioned above, the entire producer thread is found in the .serve() function. It does the following things
Initializes the semaphores. There are two version here because of OS differences. I programmed on a OS X, but had to turn in code on Linux. Since Semaphores are tied to the OS, it is important to understand how to use semaphores in your particular setup.
It sets up the socket for the client to talk to. Not important for your application.
Creates the consumer threads.
Watches the client socket and uses the producer pattern to pass items to the consumers. This code is below
At the bottom of the .serve() function you can see the following code:
while ((client = accept(server_,(struct sockaddr *)&client_addr,&clientlen)) > 0) {
sem_wait(clients_.e); //buffer check
sem_wait(clients_.s);
clients_.q->push(client);
sem_post(clients_.s);
sem_post(clients_.n); //produce
}
First, you check the buffer semaphore "e" to ensure there is room in your queue to place the request. Second, acquire the semaphore "s" for the queue. Then add your task (In this case, a client connection) to the queue. Release the semaphore for the queue. Finally, signal to the consumers using semaphore "n".
Consumer:
In the .handle() method you really only care about the very beginning of the thread.
while(1){
sem_wait(clients_.n); //consume
sem_wait(clients_.s);
client = clients_.q->front();
clients_.q->pop();
sem_post(clients_.s);
sem_post(clients_.e); //buffer free
//Handles the client requests until they disconnect.
}
The consumer does similar actions to the producer, but in opposite fashion. First the consumer waits for the producer to signal on the semaphore "n". Remember since there are multiple consumers it is completely random which consumer might end up acquiring this semaphore. They fight over it, but only one can move passed this point per sem_post of that semaphore. Second, they acquire the queue semaphore like the producer does. Pop the first item off the queue and release the semaphore. Finally, they signal on the buffer semaphore "e" that there is now more room in the buffer.
Disclaimer:
I know the semaphores have terrible names. They match my professor's slides since that's where I learned it. I think they stand for the following:
e for empty : this semaphore stops the producer from pushing more items on the queue if it is full.
s for semaphore : My least favorite. But my professor's style was to have a struct for each shared data struct. In this case "clients_" is the struct including all three semaphores and the queue. Basically this semaphore is there to ensure no two threads touch the same data structure at the same time.
n for number of items in the queue.
Ok, so to make it as simple as possible. You will need 2 threads, mutex, queue and 2 thread processing functions.
Header.h
static DWORD WINAPI ThreadFunc_Prod(LPVOID lpParam);
static DWORD WINAPI ThreadFunc_Con(LPVOID lpParam);
HANDLE m_hThread[2];
queue<int> m_Q;
mutex m_M;
Add all needed stuff, these are just core parts you need
Source.cpp
DWORD dwThreadId;
m_hThread[0] = CreateThread(NULL, 0, this->ThreadFunc_Prod, this, 0, &dwThreadId);
// same for 2nd thread
DWORD WINAPI Server::ThreadFunc_Prod(LPVOID lpParam)
{
cYourClass* o = (cYourClass*) lpParam;
int nData2Q = GetData(); // this is whatever you use to get your data
m_M.lock();
m_Q.push(nData2Q);
m_M.unlock();
}
DWORD WINAPI Server::ThreadFunc_Con(LPVOID lpParam)
{
cYourClass* o = (cYourClass*) lpParam;
int res;
m_M.lock();
if (m_Q.empty())
{
// bad, no data, escape or wait or whatever, don't block context
}
else
{
res = m_Q.front();
m_Q.pop();
}
m_M.unlock();
// do you magic with res here
}
And in the end of main - don't forget to use WaitForMultipleObjects
All possible examples can be found directly in MSDN so there is quite nice commentary about that.
PART2:
ok, so I believe header is self-explainable, so I will give you little bit more description to source. Somewhere in your source (can be even in Constructor) you create threads - the way how to create thread may differ but idea is the same (in win - thread is run right after its creation in posix u have to join). I believe u shall have somewhere a function which starts all your magic, lets call it MagicKicker()
In case of posix, create thread in constructor and join em in your MagicKicker(), win - create in MagicKicker()
Than you would need to declare (in header) two function where you thread function will be implemented ThreadFunc_Prod and ThreadFunc_Prod , important magic here is that you will pass reference to your object to this function (coz thread are basically static) so u can easy access shared resources as queues, mutexes, etc...
These function are actually doing the work. You actually have all u need in you code, just use this as adding routine in Producer:
int nData2Q = GetData(); // this is whatever you use to get your data
m_M.lock(); // locks mutex so nobody cant enter mutex
m_Q.push(nData2Q); // puts data from producer to share queue
m_M.unlock(); // unlock mutex so u can access mutex in your consumer
And add this to your consumer:
int res;
m_M.lock(); // locks mutex so u cant access anything wrapped by mutex in producer
if (m_Q.empty()) // check if there is something in queue
{
// nothing in you queue yet OR already
// skip this thread run, you can i.e. sleep for some time to build queue
Sleep(100);
continue; // in case of while wrap
return; // in case that u r running some framework with threadloop
}
else // there is actually something
{
res = m_Q.front(); // get oldest element of queue
m_Q.pop(); // delete this element from queue
}
m_M.unlock(); // unlock mutex so producer can add new items to queue
// do you magic with res here
The problem mentioned in my question was that the image displayed by the Consumer thread was not containing complete data. The image displayed by the Consumer thread contains several patches which suggest that it could not get the full data produced by Producer thread.
ANSWER The reason behind it is the declaration of Mat image inside the while loop of Consumer thread. The Mat instance created inside the while loop gets deleted once the second round of while loop starts and therefore the Producer thread was never able to access the data of Mat image created in the Consumer thread.
SOLUTION: I should have done it something like this
struct ThreadSafeContainer
{
queue<Mat> safeContainer;
};
struct Producer
{
Producer(std::shared_ptr<ThreadSafeContainer> c) : container(c)
{
}
void run()
{
while(true)
{
// grab image from camera
// store image in container
Mat image(400, 400, CV_8UC3, Scalar(10, 100,180) );
mu.lock();
container->safeContainer.push(Mat);
mu.unlock();
}
}
std::shared_ptr<ThreadSafeContainer> container;
};
struct Consumer
{
Consumer(std::shared_ptr<ThreadSafeContainer> c) : container(c)
{
}
~Consumer()
{
}
void run()
{
while(true)
{
// read next image from container
mu.lock();
if (!container->safeContainer.empty())
{
Mat image= container->safeContainer.front(); //The front of the queue contain the image
container->safeContainer.pop();
imshow("consumer image", image);
waitKey(33);
}
mu.unlock();
}
}
std::shared_ptr<ThreadSafeContainer> container;
};

c++ implementing semaphore on my own

let's pretend there are no libraries that provide semaphores for C++. I wrote this:
#include <vector>
#include <Windows.h>
class Semaphore {
HANDLE mutexS; // provides mutex in semaphore rutines
std::vector<HANDLE> queue; // provides FIFO queue for blocked threads
int value; // semaphore's value
public:
Semaphore(int init=1);
~Semaphore();
void wait();
void signal();
};
Semaphore::Semaphore(int init) {
value = init;
queue = std::vector<HANDLE>();
mutexS = CreateMutex(0,0,0);
}
Semaphore::~Semaphore() {
CloseHandle(mutexS);
}
void Semaphore::signal() {
WaitForSingleObject(mutexS, INFINITE);
if (++value <= 0) {
HANDLE someOldThread = queue.front();
ResumeThread(someOldThread);
queue.erase(queue.begin());
CloseHandle(someOldThread);
}
ReleaseMutex(mutexS);
}
I would like to know why this implementation of wait() doesn't work:
void Semaphore::wait() {
WaitForSingleObject(mutexS, INFINITE);
if (--value < 0) {
HANDLE thisThread = GetCurrentThread();
queue.push_back(thisThread);
ReleaseMutex(mutexS);
SuspendThread(thisThread );
}
else
ReleaseMutex(mutexS);
}
And this one works:
void Semaphore::wait() {
WaitForSingleObject(mutexS, INFINITE);
if (--value < 0) {
HANDLE thisThread = GetCurrentThread();
HANDLE alsoThisThread;
DuplicateHandle(GetCurrentProcess(), thisThread, GetCurrentProcess(), &alsoThisThread, 0, 0, DUPLICATE_SAME_ACCESS);
queue.push_back(alsoThisThread);
ReleaseMutex(mutexS);
SuspendThread(alsoThisThread);
}
else
ReleaseMutex(mutexS);
}
What exactly happens in each case? I've been banging my head over it for a lot of time now. The first implementation of wait, which doesn't work, makes my program block (well, it probably blocks some thread forever). The 2nd implementation works like a charm. What gives ? Why do I need to duplicate thread handles and block the duplicate ?
MSDN helps a lot here ;)
GetCurrentThread returns a pseudo-handle which is a constant for "the current thread":
A pseudo handle is a special constant that is interpreted as the current thread handle.
So when you push it in the queue, you are always pushing a constant that says "the current thread", which is obviously not what you want.
To get a real handle, you have to use DuplicateHandle
If hSourceHandle is a pseudo handle returned by GetCurrentProcess or GetCurrentThread, DuplicateHandle converts it to a real handle to a process or thread, respectively.
A final note: I suppose you are implementing this as a "test" right? Because there are several potential problems.. A very good learning exercise would be to dig them out. But you should not use this in production code.
Out of curiosity: if you want to experiment a little more, the "canonical" way of implementing semaphore with mutexes is to use two mutexes: see here
MSDN documentation for GetCurrentThread has the answer (accents are mine):
The return value is a pseudo handle for the current thread.
A pseudo handle is a special constant that is interpreted as the current thread handle. The calling thread can use this handle to specify itself whenever a thread handle is required.
...
The function cannot be used by one thread to create a handle that can be used by other threads to refer to the first thread. The handle is always interpreted as referring to the thread that is using it. A thread can create a "real" handle to itself that can be used by other threads, or inherited by other processes, by specifying the pseudo handle as the source handle in a call to the DuplicateHandle function.

pthread_cond_wait and pthread_cond_signal's performance

I have two threads.
One that reads from the a queue. I don't want it to run on while(1) to read, so I'm thinking about giving it a condition variable each looping:
while(1){
while queue is not empty
wait(cond)
pop()
}
instead of:
while(1){
while queue is not empty
pop
}
and a thread that pushes to the queue.If I use the wait and signal method , then that thread needs to notify by signaling the popping thread every time(!) it pushes
The question is what is better to use?
If the queue is mostly not empty, then it's worthless (or is it not?) to send signals because the popping thread isn't waiting and I'm afraid it would reduce performance.
However, if the queue is half the time empty, then looping on it as in the second method to pop might be a busy wait.
I'm hoping someone here would eliminate my fears by disqualifying the fact that sending a signal to a thread that's not waiting on it is still ok
Thanks
First just to make sure, pthread_cond_signal does not send a signal in the signal(2) sense. It just flags the condition variable and releases any variable that's waiting for it. So if you call pthread_cond_signal before the consuming process calls well, that's just going to be ignored.
Secondly, is pthread_cond_wait fast or slow? Well, it depends. You can use it poorly and you can use it well. If you use it poorly I'm sure it will perform terribly. If you only wait when you actually need to I think it will perform nicely.
So, since you need to hold a mutex to use condition variables, you might as well check if there is data at this point (and use this mutex as a synchronization point).
An idea for a queue data structure:
struct q {
struct qe *h;
struct qe *t;
pthread_mutex_t m;
pthread_cond_t c;
int len;
};
The consumer (assuming you only have one consumer, if you have multiple to need to lock around the head check):
void *consumer(void*arg) {
struct q *q = arg;
while(1) {
pthread_mutex_lock(&q->m);
if(q->h == NULL)
pthread_cond_wait(&q->c, &q->m);
/* We hold the mutex when we exit pthread_cond_wait */
pthread_mutex_unlock(&q->m); /* we can make the check without the mutex */
while(q->h != NULL) {
pthread_mutex_lock(&q->m); /* but we need it to modify */
pop();
pthread_mutex_unlock(&q->m);
/* Process data */
}
}
}
The producer:
void *producer(void*arg) {
int i;
struct q *q = arg;
while(1) {
pthread_mutex_lock(&q->m);
push(q, some_data);
if(q->h == q->t) /* only one element */
pthread_cond_signal(&q->c);
pthread_mutex_unlock(&q->m);
}
return NULL;
}

C++ multithreading, simple consumer / producer threads, LIFO, notification, counter

I am new to multi-thread programming, I want to implement the following functionality.
There are 2 threads, producer and consumer.
Consumer only processes the latest value, i.e., last in first out (LIFO).
Producer sometimes generates new value at a faster rate than consumer can
process. For example, producer may generate 2 new value in 1
milli-second, but it approximately takes consumer 5 milli-seconds to process.
If consumer receives a new value in the middle of processing an old
value, there is no need to interrupt. In other words, consumer will finish current
execution first, then start an execution on the latest value.
Here is my design process, please correct me if I am wrong.
There is no need for a queue, since only the latest value is
processed by consumer.
Is notification sent from producer being queued automatically???
I will use a counter instead.
ConsumerThread() check the counter at the end, to make sure producer
doesn't generate new value.
But what happen if producer generates a new value just before consumer
goes to sleep(), but after check the counter???
Here is some pseudo code.
boost::mutex mutex;
double x;
void ProducerThread()
{
{
boost::scoped_lock lock(mutex);
x = rand();
counter++;
}
notify(); // wake up consumer thread
}
void ConsumerThread()
{
counter = 0; // reset counter, only process the latest value
... do something which takes 5 milli-seconds ...
if (counter > 0)
{
... execute this function again, not too sure how to implement this ...
}
else
{
... what happen if producer generates a new value here??? ...
sleep();
}
}
Thanks.
If I understood your question correctly, for your particular application, the consumer only needs to process the latest available value provided by the producer. In other words, it's acceptable for values to get dropped because the consumer cannot keep up with the producer.
If that's the case, then I agree that you can get away without a queue and use a counter. However, the shared counter and value variables will be need to be accessed atomically.
You can use boost::condition_variable to signal notifications to the consumer that a new value is ready. Here is a complete example; I'll let the comments do the explaining.
#include <boost/thread/thread.hpp>
#include <boost/thread/mutex.hpp>
#include <boost/thread/condition_variable.hpp>
#include <boost/thread/locks.hpp>
#include <boost/date_time/posix_time/posix_time_types.hpp>
boost::mutex mutex;
boost::condition_variable condvar;
typedef boost::unique_lock<boost::mutex> LockType;
// Variables that are shared between producer and consumer.
double value = 0;
int count = 0;
void producer()
{
while (true)
{
{
// value and counter must both be updated atomically
// using a mutex lock
LockType lock(mutex);
value = std::rand();
++count;
// Notify the consumer that a new value is ready.
condvar.notify_one();
}
// Simulate exaggerated 2ms delay
boost::this_thread::sleep(boost::posix_time::milliseconds(200));
}
}
void consumer()
{
// Local copies of 'count' and 'value' variables. We want to do the
// work using local copies so that they don't get clobbered by
// the producer when it updates.
int currentCount = 0;
double currentValue = 0;
while (true)
{
{
// Acquire the mutex before accessing 'count' and 'value' variables.
LockType lock(mutex); // mutex is locked while in this scope
while (count == currentCount)
{
// Wait for producer to signal that there is a new value.
// While we are waiting, Boost releases the mutex so that
// other threads may acquire it.
condvar.wait(lock);
}
// `lock` is automatically re-acquired when we come out of
// condvar.wait(lock). So it's safe to access the 'value'
// variable at this point.
currentValue = value; // Grab a copy of the latest value
// while we hold the lock.
}
// Now that we are out of the mutex lock scope, we work with our
// local copy of `value`. The producer can keep on clobbering the
// 'value' variable all it wants, but it won't affect us here
// because we are now using `currentValue`.
std::cout << "value = " << currentValue << "\n";
// Simulate exaggerated 5ms delay
boost::this_thread::sleep(boost::posix_time::milliseconds(500));
}
}
int main()
{
boost::thread c(&consumer);
boost::thread p(&producer);
c.join();
p.join();
}
ADDENDUM
I was thinking about this question recently, and realized that this solution, while it may work, is not optimal. Your producer is using all that CPU just to throw away half of the computed values.
I suggest that you reconsider your design and go with a bounded blocking queue between the producer and consumer. Such a queue should have the following characteristics:
Thread-safe
The queue has a fixed size (bounded)
If the consumer wants to pop the next item, but the queue is empty, the operation will be blocked until notified by the producer that an item is available.
The producer can check if there's room to push another item and block until the space becomes available.
With this type of queue, you can effectively throttle down the producer so that it doesn't outpace the consumer. It also ensures that the producer doesn't waste CPU resources computing values that will be thrown away.
Libraries such as TBB and PPL provide implementations of concurrent queues. If you want to attempt to roll your own using std::queue (or boost::circular_buffer) and boost::condition_variable, check out this blogger's example.
The short answer is that you're almost certainly wrong.
With a producer/consumer, you pretty much need a queue between the two threads. There are basically two alternatives: either your code won't will simply lose tasks (which usually equals not working at all) or else your producer thread will need to block for the consumer thread to be idle before it can produce an item -- which effectively translates to single threading.
For the moment, I'm going to assume that the value you get back from rand is supposed to represent the task to be executed (i.e., is the value produced by the producer and consumed by the consumer). In that case, I'd write the code something like this:
void producer() {
for (int i=0; i<100; i++)
queue.insert(random()); // queue.insert blocks if queue is full
queue.insert(-1.0); // Tell consumer to exit
}
void consumer() {
double value;
while ((value = queue.get()) != -1) // queue.get blocks if queue is empty
process(value);
}
This, relegates nearly all the interlocking to the queue. The rest of the code for both threads pretty much ignores threading issues entirely.
Implementing a pipeline is actually quite tricky if you are doing it ground-up. For example, you'd have to use condition variable to avoid the kind of race condition you described in your question, avoid busy waiting when implementing the mechanism for "waking up" the consumer etc... Even using a "queue" of just 1 element won't save you from some of these complexities.
It's usually much better to use specialized libraries that were developed and extensively tested specifically for this purpose. If you can live with Visual C++ specific solution, take a look at Parallel Patterns Library, and the concept of Pipelines.

consumer/producer in c++

This is a classic c/p problem where some threads produce data while other read the data. Both the producer and consumers are sharing a const sized buffer. If the buffer is empty then the consumers have to wait and if it is full then the producer has to wait. I am using semaphores to keep track of full or empty queues. The producer is going to decrement free spots semaphore, add value, and increment filled slots semaphore. So I am trying to implement a program that gets some numbers from the generator function, and then prints out the average of the numbers. By treating this as a producer-consumer problem, I am trying to save some time in the execution of the program. The generateNumber function causes some delay in the process so I want to create a number of threads that generate numbers, and put them into a queue. Then the "main thread" which is running the main function has to read from the queue and find the sum and then average. So here is what I have so far:
#include <cstdio>
#include <cstdlib>
#include <time.h>
#include "Thread.h"
#include <queue>
int generateNumber() {
int delayms = rand() / (float) RAND_MAX * 400.f + 200;
int result = rand() / (float) RAND_MAX * 20;
struct timespec ts;
ts.tv_sec = 0;
ts.tv_nsec = delayms * 1000000;
nanosleep(&ts, NULL);
return result; }
struct threadarg {
Semaphore filled(0);
Semaphore empty(n);
std::queue<int> q; };
void* threadfunc(void *arg) {
threadarg *targp = (threadarg *) arg;
threadarg &targ = *targp;
while (targ.empty.value() != 0) {
int val = generateNumber();
targ.empty.dec();
q.push_back(val);
targ.filled.inc(); }
}
int main(int argc, char **argv) {
Thread consumer, producer;
// read the command line arguments
if (argc != 2) {
printf("usage: %s [nums to average]\n", argv[0]);
exit(1); }
int n = atoi(argv[1]);
// Seed random number generator
srand(time(NULL));
}
I am a bit confused now because I am not sure how to create multiple producer threads that are generating numbers (if q is not full) while the consumer is reading from the queue (that is if q is not empty). I am not sure what to put in the main to implment it.
also in "Thread.h", you can create a thread, a mutex, or a semaphore. The thread has the methods .run(threadFunc, arg), .join(), etc. A mutex can be locked or unlocked. The semaphore methods have all been used in my code.
Your queue is not synchronized, so multiple producers could call push_back at the same time, or at the same time the consumer is calling pop_front ... this will break.
The simple approach to making this work is to use a thread-safe queue, which can be a wrapper around the std::queue you already have, plus a mutex.
You can start by adding a mutex, and locking/unlocking it around each call you forward to std::queue - for a single consumer that should be sufficient, for multiple consumers you'd need to fuse front() and pop_front() into a single synchronized call.
To let the consumer block while the queue is empty, you can add a condition variable to your wrapper.
That should be enough that you can find the answer online - sample code below.
template <typename T> class SynchronizedQueue
{
std::queue<T> queue_;
std::mutex mutex_;
std::condition_variable condvar_;
typedef std::lock_guard<std::mutex> lock;
typedef std::unique_lock<std::mutex> ulock;
public:
void push(T const &val)
{
lock l(mutex_); // prevents multiple pushes corrupting queue_
bool wake = queue_.empty(); // we may need to wake consumer
queue_.push(val);
if (wake) condvar_.notify_one();
}
T pop()
{
ulock u(mutex_);
while (queue_.empty())
condvar_.wait(u);
// now queue_ is non-empty and we still have the lock
T retval = queue_.front();
queue_.pop();
return retval;
}
};
Replace std::mutex et al with whatever primitives your "Thread.h" gives you.
What I would do is this:
Make a data class that hides your queue
Create thread-safe accessor methods for saving a piece of data to the q, and removing a piece of data from the q ( I would use a single mutex, or a critical section for accessors)
Handle the case where a consumor doesn't have any data to work with (sleep)
Handle the case where the q is becoming too full, and the producers need to slow down
Let the threads go willy-nilly adding and removing as they produce / consume
Also, remember to add a sleep into each and every thread, or else you'll peg the CPU and not give the thread scheduler a good spot to switch contexts and share the CPU with other threads / processes. You don't need to, but it's a good practice.
When managing shared state like this, you need a condition variable and
a mutex. The basic pattern is a function along the lines of:
ScopedLock l( theMutex );
while ( !conditionMet ) {
theCondition.wait( theMutex );
}
doWhatever();
theCondition.notify();
In your case, I'd probably make the condition variable and the mutex
members of the class implementing the queue. To write, the
conditionMet would be !queue.full(), so you'd end up with something
like:
ScopedLock l( queue.myMutex );
while ( queue.full() ) {
queue.myCondition.wait();
}
queue.insert( whatever );
queue.myCondition.notify();
and to read:
ScopedLock l( queue.myMutex );
while ( queue.empty() ) {
queue.myCondition.wait();
}
results = queue.extract();
queue.myCondition.notify();
return results;
Depending on the threading interface, there may be two notify
functions: notify one (which wakes up a single thread), and notify all
(which wakes up all of the waiting threads); in this case, you'll need
notify all (or you'll need two condition variables, one for space to
write, and one for something to read, with each function waiting on one,
but notifying the other).
Protect the queue accesses with a mutex, that should be it. A 'Computer Science 101' bounded producer-consumer queue needs two semaphores, (to manage the free/empty count and for producers/consumers to wait on, as you are already doing), and one mutex/futex/criticalSection to protect the queue.
I don't see how replacing the semaphores and mutex with condvars is any great help. What's the point? How do you implement a bounded producer-consumer queue with condvars that works on all platforms with multiple producers/consumers?
#include<iostream>
#include<deque>
#include<mutex>
#include<chrono>
#include<condition_variable>
#include<thread>
using namespace std;
mutex mu,c_out;
condition_variable cv;
class Buffer
{
public:
Buffer() {}
void add(int ele)
{
unique_lock<mutex> ulock(mu);
cv.wait(ulock,[this](){return q.size()<_size;});
q.push_back(ele);
mu.unlock();
cv.notify_all();
return;
}
int remove()
{
unique_lock<mutex> ulock(mu);
cv.wait(ulock,[this](){return q.size()>0;});
int v=q.back();
q.pop_back();
mu.unlock();
cv.notify_all();
return v;
}
int calculateAvarage()
{
int total=0;
unique_lock<mutex> ulock(mu);
cv.wait(ulock,[this](){return q.size()>0;});
deque<int>::iterator it = q.begin();
while (it != q.end())
{
total += *it;
std::cout << ' ' << *it++;
}
return total/q.size();
}
private:
deque<int> q;
const unsigned int _size=10;
};
class Producer
{
public:
Producer(Buffer *_bf=NULL)
{
this->bf=_bf;
}
void Produce()
{
while(true)
{
int num=rand()%10;
bf->add(num);
c_out.lock();
cout<<"Produced:"<<num<<"avarage:"<<bf->calculateAvarage()<<endl;
this_thread::sleep_for(chrono::microseconds(5000));
c_out.unlock();
}
}
private:
Buffer *bf;
};
class Consumer
{
public:
Consumer(Buffer *_bf=NULL)
{
this->bf=_bf;
}
void Consume()
{
while (true)
{
int num=bf->remove();
c_out.lock();
cout<<"Consumed:"<<num<<"avarage:"<<bf->calculateAvarage()<<endl;
this_thread::sleep_for(chrono::milliseconds(5000));
c_out.unlock();
}
}
private:
Buffer *bf;
};
int main()
{
Buffer b;
Consumer c(&b);
Producer p(&b);
thread th1(&Producer::Produce,&p);
thread th2(&Consumer::Consume,&c);
th1.join();
th2.join();
return 0;
}
Buffer class has doublended queue and max Buffer size of 10.
It has two function to add into queue and remove from queue.
Buffer class has calculateAvarage() function which will calculate the avarage echa time a element is added or deleted.
There are two more classes one is producer and consumer having buffwr class pointer .
We are having Consume() in consumer class and Produce() in Producer class.
Consume()>>Lock the buffer and check if size is of buffer is not 0 it will remove from Buffer and notify to producer and unlock.
Produce()>>Lok the buffer and check if size is of buffer is not max buffer size it will add and notify to consumer and unlock.