Having set amount of thread to work as consumers - c++

I have created a producer / consumer code as following
class CTest{
public:
void producer( int i ){
unique_lock<mutex> l(m);
q.push(i);
if( q.size() )
cnd.notify_all();
}
void consumer(int i ){
unique_lock<mutex> l(m);
while( q.empty() ){
cnd.wait(l );
}
if( q.empty())
return;
cout << "IM AWAKE :" << i << endl;
int tmp = q.front();
q.pop();
l.unlock();
cout << "Producer got " << tmp << endl;
}
void ConsumerInit( int threads ){
for( int i = 0; i < threads; i++ ){
thrs.push_back(thread(&CTest::consumer, this ,i));
}
}
void waitForTHreads(){
for( auto &a : thrs )
a.join();
}
void printQueue(){
while( ! q.empty()){
int tmp = q.front();
q.pop();
cout << "Queue got " << tmp << endl;
}
}
private:
queue<int> q;
vector<thread> thrs;
mutex m;
condition_variable cnd;
};
and main
int main(){
int x;
CTest t;
int counter = 0;
while( cin >> x ){
if( x == 0 ){
cout << "yay" << endl;;
break;
}
if( x == 1)
t.producer(counter++);
if( x == 2 )
t.ConsumerInit(5);
}
t.waitForTHreads();
t.printQueue();
return 0;
}
What this code does it , when user inputs "1" it will add number to the queue ,when user inputs "2" , 5 threads are spawned to retrieve data from queue and print it. However my problem is as followng , when i input
6 numbers , only 5 of them are printed due to fact that only 5 threads are spawned , what i want to do is thread to retrieve a data from queue , print int, and then again waiting if it can print another data. This way all N > 5 numbers would pri printed with just 5 threads.
My question is , what is standard way how to achieve this? I read few documens but didnt fint/cannot think of good solution. How are problems like this solved?
when i try to create simple thread pool :
void consumer(int i ){
while(true){
{
unique_lock<mutex> l(m);
while( q.empty() ){
cnd.wait(l );
}
if( q.empty())
return;
cout << "IM AWAKE :" << i << endl;
int tmp = q.front();
q.pop();
cout << "Producer " << i << " got " << tmp << endl;
} //consumer(i);
}
}
and input N number all numbers are processed by one thread.
Thanks for help!

The current version of consumer can only read one value before exiting. In order to read more, it must loop, and this leads to your second version of consumer which has two problems:
Consumption here is so quick that the first thread into the queue can consume the whole queue within its timeslice (or however CPU is being allocated). Insert a yield or a sleep to force the OS to switch tasks.
The mutex is not unlocked so no other threads are able to get in.
Fortunately you aren't creating the threads until you need them and they terminate after the queue is empty so the whole deal with conditional_variable can go out the window.
void consumer(int i)
{
unique_lock<mutex> l(m);
while (!q.empty())
{
int tmp = q.front();
q.pop();
cout << i << " got " << tmp << endl;
// note: In the real world, locking around a cout is gross. cout is slow,
// so you want the unlock up one line. But...! This allows multiple threads
// to write to the consle at the same time and that makes your output
// look like it was tossed into a blender, so we'll take the performance hit
l.unlock(); // let other threads have a turn
this_thread::yield();
l.lock(); // lock again so the queue can be safely inspected
}
}
If you need to go with the threadpool approach, things get a little messier and the condition variable makes a return.
void consumer(int i)
{
while (true)
{
unique_lock<mutex> l(m);
if (q.empty())
{
cnd.wait(l);
}
if (!q.empty()) // OK. We got out of the conditional wait, but have
// other threads sucked the queue dry? Better check.
{
int tmp = q.front();
q.pop();
cout << i << " got " << tmp << endl;
}
l.unlock();
this_thread::yield();
}
}
An atomic<bool> terminated may be helpful to allow an orderly shutdown while (true) does not allow for.

In general, without going into code details, a threadpool is created and the threads are put in a wait state (waiting on one or more events / signals, or in your case condition_variable cnd;) - I'm used to work with events, so I'll use that in the following text, but a condition_variable should work in a similar way.
When a task is added to the queue, a task-event is set/fired and one ore more threads wake up (depending on the event (single / multi)).
When a thread wakes up, it checks (with a lock) if there is a task available, if available, executes the task and when finished checks again (!) if there are more tasks waiting. (because when you add 8 tasks in one go, 5 threads become active, so they need to check if there are more tasks after finishing their first one.
If there are no jobs left, the thread goes back in the wait state (waiting for a next job, or a quit event).
When quitting the application, another, say quit-event, is set for all threads (you can't just wait for the threads to finish, because the threads themselves are waiting on an event to do some work) -- or you could fire the same event, and first set a volatile variable, which the threads should then first check on any event to see if they need to quit, or do another job. Then you can wait for the threads to 'come home'.
A lock should be held as short as possible.
As for your code:
void producer( int i ){
unique_lock<mutex> l(m);
q.push(i);
if( q.size() )
cnd.notify_all();
}
Here the lock is held longer than needed (and perhaps too long). You also just pushed a value, so q will not be empty (no need to check). Since you only add one item (task), only one thread should be woken up (so notify_one() should be fine here).
So you should: lock, push, unlock, notify - instead of unlock, you can place the lock and push inside brackets, which will trigger an unlock in the unique_lock<> destructor.
void consumer(int i ){
unique_lock<mutex> l(m);
while( q.empty() ){
cnd.wait(l );
}
if( q.empty())
return;
cout << "IM AWAKE :" << i << endl;
int tmp = q.front();
q.pop();
l.unlock();
cout << "Producer got " << tmp << endl;
}
Here you should lock, check queue, pop if there is a task, unlock, if no task, put the thread in a wait state again, else do work with the popped value (after unlocking), and then check again if there is more work to do. Normally it is not a good idea to call cout while the data is locked.. but for a small test you could get away with it, especially because cout needs to be synchronized too (but it would be cleaner to synchronize cout on its own, separate from your data lock).
void printQueue(){
while( ! q.empty()){
int tmp = q.front();
q.pop();
cout << "Queue got " << tmp << endl;
}
}
Make sure your data is locked here too! (although it's only called from main after the threads have finished, the function is in your class, and the data should be locked).

Related

Same thread keeps getting rescheduled after yielding

I am trying to create a very threaded simple producer consumer toy implementation, but I'm running into a strange issue where the same consumer thread keeps getting rescheduled over and over again even though I am yielding control.
Here is an abridged version of my code. The Main method is simple , I start one producer and two consumer threads. I join to the producer thread and detach the two consumer threads. A getchar at the end of the main method keeps the program from exiting.
std::vector<int> UnprocessedValues;
std::vector<int> ProcessedValues;
std::mutex unprocessed_mutex;
void AddUnprocessedValue()
{
for (int i = 0; i <= 1000; ++i)
{
{
std::lock_guard<std::mutex> guard(unprocessed_mutex);
UnprocessedValues.push_back(i);
std::cout << "Thread id : " << std::this_thread::get_id() << " ";
printf("Unprocessed value added %i \n", UnprocessedValues.back());
}
}
}
void ProcessCurrentValue()
{
while (true)
{
unprocessed_mutex.lock();
if (UnprocessedValues.empty())
{
std::cout << "Thread id : " << std::this_thread::get_id() << " ";
printf("is waiting for values \n");
unprocessed_mutex.unlock();
std::this_thread::yield();
}
else
{
// Process value
unprocessed_mutex.unlock();
}
}
}
I expect that when there are no values present for consumers, they will both yield and end up giving the producer a chance to produce more.
In practice I see a single consumer getting stuck on waiting for values. Eventually the program rights itself, but something is obviously wrong.
If I was seeing the two consumers print that they are waiting in alternate, I would think that somehow the producer is getting shafted by the two consumers taking turns, but the actual result is that the same thread keeps getting rescheduled even though it just yielded.
Finally, when I change the if case from
if (UnprocessedValues.empty())
{
std::cout << "Thread id : " << std::this_thread::get_id() << " ";
printf("is waiting for values \n");
unprocessed_mutex.unlock();
std::this_thread::yield();
}
to
if (UnprocessedValues.empty())
{
unprocessed_mutex.unlock();
std::this_thread::yield();
std::cout << "Thread id : " << std::this_thread::get_id() << " ";
printf("is waiting for values \n");
}
I never see a busy wait. I realize that I could use a condition variable to fix this problem and I have already seen that using a small sleep instead of a yield works. I am just trying to understand why the yield would not work.

Producer Consumer problem using mutexes in cpp

I have a single producer and 2 consumers threads trying to acess a shared buffer. Mutex locks are used between consumer and producer. Consumers are supposed to run paralelly. If buffer is empty, consumer sleeps and producer has to wake them. If buffer is full, producer does not do anything. Below is the code snippets I am working on:
Producer thread:
void *writer(void*)
{
// Initialising the seed
srand(time(NULL));
while(1)
{
pthread_mutex_lock(&rallow);
if (Q.size() < MAX && item < MAX)
{
// Getting the random number
int num = rand() % 10 + 1;
// Pushing the number into queue
Q.push(num);
item++;
cout << "Produced: " << num << " item: "<<item<<endl;
pthread_cond_broadcast(&dataNotProduced);
}
else if (item == MAX) {
pthread_mutex_unlock(&rallow);
continue;
}
pthread_mutex_unlock(&rallow);
}
}
COnsumer 1:
void *reader1(void*)
{
while(1)
{
pthread_mutex_lock(&mread);
rc++;
if(rc==1)
pthread_mutex_lock(&rallow);
pthread_mutex_unlock(&mread);
if (Q.size() > 0) {
// Get the data from the front of queue
int data = Q.front();
// Pop the consumed data from queue
Q.pop();
item--;
cout << "B thread consumed: " << data <<endl;
pthread_cond_signal(&dataNotConsumed);
}
else
{
cout << "B is in wait.." << endl;
pthread_cond_wait(&dataNotProduced, &rallow);
cout<<"B woke up"<<endl;
}
pthread_mutex_lock(&mread);
rc--;
if(rc==0)
pthread_mutex_unlock(&rallow);
pthread_mutex_unlock(&mread);
sleep(1);
}
}
Consumer 2:
void *reader2(void*)
{
while(1)
{
pthread_mutex_lock(&mread);
rc++;
if(rc==1)
pthread_mutex_lock(&rallow);
pthread_mutex_unlock(&mread);
if (Q.size() > 0) {
// Get the data from the front of queue
int data = Q.front();
// Pop the consumed data from queue
Q.pop();
item--;
cout << "C thread consumed: " << data <<endl;
pthread_cond_signal(&dataNotConsumed);
}
else
{
cout << "C is in wait.." << endl;
pthread_cond_wait(&dataNotProduced, &rallow);
cout<<"C woke up"<<endl;
}
pthread_mutex_lock(&mread);
rc--;
if(rc==0)
pthread_mutex_unlock(&rallow);
pthread_mutex_unlock(&mread);
sleep(1);
}
}
The output looks something like this:
C is in wait..
B is in wait..
Produced: 8 item: 1
Produced: 4 item: 2
Produced: 2 item: 3
Produced: 4 item: 4
Produced: 2 item: 5
Produced: 8 item: 6
Produced: 5 item: 7
Produced: 2 item: 8
Produced: 10 item: 9
Produced: 3 item: 10
>> Producer is in wait..
B woke up
B thread consumed: 8
B thread consumed: 4
B thread consumed: 2
B thread consumed: 4
B thread consumed: 2
B thread consumed: 8
B thread consumed: 5
B thread consumed: 2
B thread consumed: 10
B thread consumed: 3
B is in wait..
C woke up
C is in wait..
Producer woke up
My doubt is why threads B and C not showing parallel execution. And why does producer fill values into the buffer 10 at a time, rather than giving few, and then consumers consuming it, then again producing few. ANy leads would be highly appreciated.
else if (item == MAX) {
pthread_mutex_unlock(&rallow);
cout << ">> Producer is in wait.." << endl;
pthread_cond_wait(&dataNotConsumed, &rallow);
You unlock the mutex and then wait. You can't do that. That creates a window during which the thing you are waiting for can occur before you wait. You must call pthread_cond_wait while holding the mutex to ensure that the thing you are waiting for doesn't happen after you've decided to wait but before you've started waiting.
You have another huge bug in your consumer. One thread can lock rallow and then another thread can try to unlock it. That's not allowed -- the thread that acquires the mutex must be the one to release it. You don't need two mutexes -- just use one that protects all state.
First of all, there is no guarantee that all threads will run concurrently all the time. If they run on a single core, the operating system will give time slices of tens of milliseconds to each thread. And if they are running on different cores, then there is a latency between one thread calling pthread_cond_broadcast() and another thread waking up from a pthread_cond_wait(). This easily explains the writer thread being able to push 10 items to the queue before another thread wakes up.
The next issue is, why does B consume all the items, and C gets nothing? The problem is because of this:
pthread_mutex_lock(&mread);
rc++;
if(rc == 1)
pthread_mutex_lock(&rallow);
pthread_mutex_unlock(&mread);
Consider threads B and C each executing this block right after each other. Both will be able to lock mread, both will increment rc, but only one will have locked rallow. What happens next is undefined, because they both try to access the queue, even though one of them will not be holding the lock.
There should be no need to have two mutexes. Both consumer threads should just lock rallow unconditionally, check if there is something in the queue, and if not call pthread_cond_wait().
Since you are using C++, you should really use C++11's thread support instead of using the C pthread functions. Your code should then look like:
#include <iostream>
#include <thread>
#include <mutex>
#include <condition_variable>
std::mutex rallow;
std::condition_variable dataProduced;
std::condition_variable dataConsumed;
void writer() {
while(true) {
// Generate the random number
int num = rand() % 10 + 1;
std::cout << "Produced: " << num << "\n";
// Push it to the queue
{
std::lock_guard<std::mutex> lock(rallow);
dataConsumed.wait(rallow, [](){return Q.size() < MAX;});
Q.push(num);
}
}
}
void reader(int id) {
while(true) {
int data;
// Pop an item from the queue
{
std::lock_guard<std::mutex> lock(rallow);
dataProduced.wait(rallow, [](){return Q.size() > 0;});
data = Q.front();
Q.pop();
}
// Process the data
std::cout << "Consumer thread " << id << " consumed: " << data << "\n";
}
}
You could even create a thread-safe queue class that handles the mutexes and condition variables itself, so the producer and consumer code would reduce to:
void writer() {
while(true) {
int num = rand() % 10 + 1;
std::cout << "Produced: " << num << "\n";
Q.push(num);
}
}
void reader(int id) {
while(true) {
int data = Q.pop();
std::cout << "Consumer thread " << id << " consumed: " << data << "\n";
}
}

Synchronize threads using mutex

I'm trying to understand C++ Multithreading and synchronize between many threads.
Thus I created 2 threads the first one increments a value and the second one decrements it. what I can't understand why the resulted value after the execution is different than the first one, since I added and subtracted from the same value.
static unsigned int counter = 100;
static bool alive = true;
static Lock lock;
std::mutex mutex;
void add() {
while (alive)
{
mutex.lock();
counter += 10;
std::cout << "Counter Add = " << counter << std::endl;
mutex.unlock();
}
}
void sub() {
while (alive)
{
mutex.lock();
counter -= 10;
std::cout << "Counter Sub = " << counter<< std::endl;
mutex.unlock();
}
}
int main()
{
std::cout << "critical section value at the start " << counter << std::endl;
std::thread tAdd(add);
std::thread tSub(sub);
Sleep(1000);
alive = false;
tAdd.join();
tSub.join();
std::cout << "critical section value at the end " << counter << std::endl;
return 0;
}
Output
critical section value at the start 100
critical section value at the end 220
So what I need is how to keep my value as it's, I mean counter equal to 100 using those two threads.
The problem is that both threads will get into an "infinite" loop for 1 second and they will get greedy with the mutex. Do a print in both functions and see which thread gets the lock more often.
Mutexes are used to synchronize access to resources so that threads will not read/write incomplete or corrupted data, not create a neat sequence.
If you want to keep that value at 100 at the end of execution you need to use a semaphore so that there will be an ordered sequence of access to the variable.
I think, what you want is to signal to the subtracting thread, that you just have sucessfully added in the add thread, and vice versa. You'll have to additionally communicate the information, which thread is next. A naive solution:
bool shouldAdd = true;
add() {
while( alive ) {
if( shouldAdd ) {
// prefer lock guards over lock() and unlock() for exception safety
std::lock_guard<std::mutex> lock{mutex};
counter += 10;
std::cout << "Counter Add = " << counter << std::endl;
shouldAdd = false;
}
}
}
sub() {
while( alive ) {
if( !shouldAdd ) {
std::lock_guard<std::mutex> lock{mutex};
counter -= 10;
std::cout << "Counter Sub = " << counter << std::endl;
shouldAdd = true;
}
}
}
Now add() will busy wait for sub() to do its job before it will try and acquire the lock again.
To prevent busy waiting, you might chose a condition variable, instead of trying to only use a single mutex. You can wait() on the condition variable, before you add or subtract, and notify() the waiting thread afterwards.

bathroom synchronization and queue of threads

For homework we have been given the bathroom synchronization problem. I have been struggling trying to figure out how to start. What I would like to do when a person enter the restroom(personEnterRestrrom function), if they are female and no males are in the restroom they enter,if not they go into a queue for women waiting. I want to do the same for men. I tried to implement a queue that holds thread, but cannot get it to work. Then in personLeavesRestroom function. When a person leaves if no one is left in the bathroom the other queue starts. Here is my code, I know I am far off, by I do need some guidance and am not very familiar with semaphores.
//declarations
pthread_mutex_t coutMutex;
int menInBath;
int womanInBath;
int menWaiting;
int womenWaiting;
queue<pthread_mutex_t>men;
queue<pthread_mutex_t>women;
personEnterRestroom(int id, bool isFemale)
{
// LEAVE THESE STATEMENTS
pthread_mutex_lock(&coutMutex);
cout << "Enter: " << id << (isFemale ? " (female)" : " (male)") << endl;
pthread_mutex_unlock(&coutMutex);
// TODO: Complete this function
if(isFemale && menInBath<=0)
{
womanInBath++;
}
else if(isFemale && menInBath>0)
{
wait(coutMutex);
women.push(coutMutex);
}
else if(!isFemale && womanInBath<=0)
{
menInBath++;
}
else
{
wait(coutMutex);
men.push(coutMutex);
}
}
void
personLeaveRestroom(int id, bool isFemale)
{
// LEAVE THESE STATEMENTS
pthread_mutex_lock(&coutMutex);
cout << "Leave: " << id << (isFemale ? " (female)" : " (male)") << endl;
pthread_mutex_unlock(&coutMutex);
if(isFemale)
womanInBath--;
if(womanInBath==0)
{
while(!men.empty())
{
coutMutex=men.front();
men.pop();
signal(coutMutex);
}
}
}
If you are looking for FIFO mutex, this one could help you:
You gonna need:
mutex (pthread_mutex_t mutex),
array of condition variables (std::vector<pthread_cond_t> cond)
and queue for storing thread IDs (std::queue<int> fifo).
Let's say there is N threads with IDs 0 to N-1. Then fifo_lock() and fifo_unlock() could look like this (pseudocode):
fifo_lock()
tid = ID of this thread;
mutex_lock(mutex);
fifo.push(tid); // puts this thread at the end of queue
// make sure that first thread in queue owns the mutex:
while (fifo.front() != tid)
cond_wait(cond[tid], mutex);
mutex_unlock(mutex);
fifo_unlock()
mutex_lock(mutex);
fifo.pop(); // removes this thread from queue
// "wake up" first thread in queue:
if (!fifo.empty())
cond_signal(cond[fifo.front()]);
mutex_unlock(mutex);

Still having race condition with boost::mutex

I am trying an example, which causes race condition to apply the mutex. However, even with the mutex, it still happens. What's wrong? Here is my code:
#include <iostream>
#include <boost/thread.hpp>
#include <vector>
using namespace std;
class Soldier
{
private:
boost::thread m_Thread;
public:
static int count , moneySpent;
static boost::mutex soldierMutex;
Soldier(){}
void start(int cost)
{
m_Thread = boost::thread(&Soldier::process, this,cost);
}
void process(int cost)
{
{
boost::mutex::scoped_lock lock(soldierMutex);
//soldierMutex.lock();
int tmp = count;
++tmp;
count = tmp;
tmp = moneySpent;
tmp += cost;
moneySpent = tmp;
// soldierMutex.unlock();
}
}
void join()
{
m_Thread.join();
}
};
int Soldier::count, Soldier::moneySpent;
boost::mutex Soldier::soldierMutex;
int main()
{
Soldier s1,s2,s3;
s1.start(20);
s2.start(30);
s3.start(40);
s1.join();
s2.join();
s3.join();
for (int i = 0; i < 100; ++i)
{
Soldier s;
s.start(30);
}
cout << "Total soldier: " << Soldier::count << '\n';
cout << "Money spent: " << Soldier::moneySpent << '\n';
}
It looks like you're not waiting for the threads started in the loop to finish. Change the loop to:
for (int i = 0; i < 100; ++i)
{
Soldier s;
s.start(30);
s.join();
}
edit to explain further
The problem you saw was that the values printed out were wrong, so you assumed there was a race condition in the threads. The race in fact was when you printed the values - they were printed while not all the threads had a chance to execute
Based on this and your previous post (were it does not seem you have read all the answers yet). What you are looking for is some form of synchronization point to prevent the main() thread from exiting the application (because when the main thread exits the application all the children thread die).
This is why you call join() all the time to prevent the main() thread from exiting until the thread has exited. As a result of your usage though your loop of threads is not parallel and each thread is run in sequence to completion (so no real point in using the thread).
Note: join() like in Java waits for the thread to complete. It does not start the thread.
A quick look at the boost documentation suggests what you are looking for is a thread group which will allow you to wait for all threads in the group to complete before exiting.
//No compiler so this is untested.
// But it should look something like this.
// Note 2: I have not used boost::threads much.
int main()
{
boost::thread_group group;
boost::ptr_vector<boost::thread> threads;
for(int loop = 0; loop < 100; ++loop)
{
// Create an object.
// With the function to make it start. Store the thread in a vector
threads.push_back(new boost::thread(<Function To Call>));
// Add the thread to the group.
group.add(threads.back());
}
// Make sure main does not exit before all the threads have completed.
group.join_all();
}
If we go back to your example and retrofit your Soldier class:
int main()
{
boost::thread batallion;
// Make all the soldiers part of a group.
// When you start the thread make the thread join the group.
Soldier s1(batallion);
Soldier s2(batallion);
Soldier s3(batallion);
s1.start(20);
s2.start(30);
s3.start(40);
// Create 100 soldiers outside the loo
std::vector<Soldier> lotsOfSoldiers;
lotsOfSoldiers.reserve(100); // to prevent reallocation in the loop.
// Because you are using objects we need to
// prevent copying of them after the thread starts.
for (int i = 0; i < 100; ++i)
{
lotsOfSoldiers.push_back(Solder(batallion));
lotsOfSoldiers.back().start(30);
}
// Print out values while threads are still running
// Note you may get here before any thread.
cout << "Total soldier: " << Soldier::count << '\n';
cout << "Money spent: " << Soldier::moneySpent << '\n';
batallion.join_all();
// Print out values when all threads are finished.
cout << "Total soldier: " << Soldier::count << '\n';
cout << "Money spent: " << Soldier::moneySpent << '\n';
}