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.
Related
I have a sample code:
#include <iostream> // std::cout
#include <thread> // std::thread
void pause_thread(int n)
{
if(n != 4)
{
std::this_thread::sleep_for(std::chrono::seconds(100));
std::cout << "pause of " << 100 << " seconds ended\n";
}
std::cout << "Thread number " << n << " ended\n";
}
int main()
{
std::thread threads[6]; // default-constructed threads
std::setvbuf(stdout, NULL, _IONBF, 0);
std::cout << "Spawning 5 threads...\n";
for(int i = 0; i < 5; ++i)
{
//If the object is currently not joinable, it acquires the thread of execution represented by rhs (if any).
//If it is joinable, terminate() is called. If it is joinable, terminate() is called.
//rhs no longer represents any thread of execution
threads[i] = std::move(std::thread(pause_thread, i)); // move-assign threads
}
std::thread& i = threads[4];
threads[5] = std::move(threads[4]);
std::cout << "Done spawning threads. Now waiting for them to join:\n";
for(int i = 0; i < 6; ++i)
{
if(threads[i].joinable())
{
std::cout << "Thread " << i << " " << threads[i].get_id() << " ID joinable" << std::endl << std::flush;
threads[i].join();
}
else
{
std::cout << "Thread " << i << " not joinable" << std::endl << std::flush;
}
}
std::cout << "All threads joined!\n";
return 0;
}
Below is the output I received:
Spawning 5 threads...
Done spawning threads. Now waiting for them to join:
Thread 0 22476 ID joinable
Thread number 4 ended
.... no output for 100 seconds ..
pause of 100 seconds ended
Thread number 0 ended
pause of 100 seconds ended
Thread 1 28676 ID joinable
pause of 100 seconds ended
Thread number 2 ended
Thread number 3 ended
pause of 100 seconds ended
Thread number 1 ended
Thread 2 2336 ID joinable
Thread 3 42236 ID joinable
Thread 4 not joinable
Thread 5 35940 ID joinable
All threads joined!
How the "Thread n xxxx ID joinable" statements are getting printed after "Thread number n ended"? I have even tried using set std::output as non buffered but the output was same?
"Joinable" does not imply that the thread is still executing.
You first join thread #0. This will take ~100 seconds.
During that time, thread #4 finishes since it doesn't sleep, and the other threads are sleeping.
If the threads happen to be scheduled differently, any of the "sleep threads" could be printing that they've ended here.
Once the wait for thread #0 is over, you start joining the other threads.
Some of these have finished executing before you join them and some haven't.
In this particular instance, none of them finished before the wait for thread #0 was over, but there is no guarantee of that happening.
And note that a line like
std::cout << "Thread number " << n << " ended\n";
is not atomic and characters from different threads can be interleaved.
Because joinable does not mean what you think : https://en.cppreference.com/w/cpp/thread/thread/joinable
So any thread that is started is "joinable" it does not need to have finished running.
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";
}
}
I'm trying to figure out how to use std::condition_variable in C++ implementing a "strange" producer and consumer program in which I had set a limit to the count variable.
The main thread ("producer") increments the count and must wait for this to return to zero to issue a new increment.
The other threads enters in a loop where they have to decrease the counter and issue the notification.
I am blocked because it is not clear to me how to conclude the program by orderly exiting the while loop inside the function of all threads.
Could someone give me some guidance on how to implement it, please?
Code
#include <iostream>
#include <thread>
#include <condition_variable>
#include <vector>
int main() {
int n_core = std::thread::hardware_concurrency();
std::vector<std::thread> workers;
int max = 100;
int count = 0;
std::condition_variable cv;
std::mutex mutex;
int timecalled = 0;
for (int i = 0; i < n_core; i++) {
workers.emplace_back(std::thread{[&max, &count, &mutex, &cv]() {
while (true) {
std::unique_lock<std::mutex> lk{mutex};
std::cout << std::this_thread::get_id() << " cv" << std::endl;
cv.wait(lk, [&count]() { return count == 1; });
std::cout << std::this_thread::get_id() << " - " << count << std::endl;
count--;
std::cout << std::this_thread::get_id() << " notify dec" << std::endl;
cv.notify_all();
}
}});
}
while (max > 0) {
std::unique_lock<std::mutex> lk{mutex};
std::cout << std::this_thread::get_id() << " cv" << std::endl;
cv.wait(lk, [&count]() { return count == 0; });
std::cout << std::this_thread::get_id() << " created token" << std::endl;
count++;
max--;
timecalled++;
std::cout << std::this_thread::get_id() << " notify inc" << std::endl;
cv.notify_all();
}
for (auto &w : workers) {
w.join();
}
std::cout << timecalled << std::endl; // must be equal to max
std::cout << count << std::endl; // must be zero
}
Problem
The program doesn't end because it is stuck on some final join.
Expected Result
The expected result must be:
100
0
Edits Made
EDIT 1 : I replaced max > 0 in the while with a true. Now the loops are unbounded, but using the solution of #prog-fh seems to work.
EDIT 2 : I added a variable to check the result in the end.
EDIT 3: I changed while(true) to while(max >0). Could this be a problem in concurrency because we are reading it without a lock?
The threads are waiting for something new in the call cv.wait().
But the only change that can be observed with the provided lambda-closure is the value of count.
The value of max must be checked too in order to have a chance to leave this cv.wait() call.
A minimal change in your code could be
cv.wait(lk, [&max, &count]() { return count == 1 || max<=0; });
if(max<=0) break;
assuming that changes to max always occur under the control of the mutex.
An edit to clarify around the accesses to max.
If the loop run by the threads is now while(true), then the max variable is only read in its body which is synchronised by mutex (thanks to lk).
The loop run by the main program is while (max > 0): max is read without synchronisation here but the only thread that can change this variable is the main program itself, so it's pure serial code from this perspective.
The whole body of this loop is synchronised by mutex (thanks to lk) so it is safe to change the value of max here since the read operations in the threads are synchronised in the same way.
You're having race conditions: in your code max may be read by multiple threads, whilst it is being modified in main, which is a race condition according to C++ standard.
The predicates you are using in wait seems to be incorrect (you're using ==).
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).
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.