C++ multi-threading Error: Single producer Multiple consumer - c++

I am trying to achieve Single producer Multiple consumer , however below code is not able to compile.
Can someone help with this error ? Also would it work to wake all threads from this pool & a random thread would be able to acquire the lock?
TIA
`
threadPool/main.cpp:4:
/Library/Developer/CommandLineTools/usr/bin/../include/c++/v1/thread:364:17:
error: no matching constructor for initialization of '_Gp' (aka
'tuple<unique_ptrstd::__1::__thread_struct, void (TestClass::*)(),
TestClass>')
new _Gp(std::move(__tsp),
^ ~~~~~~~~~~~~~~~~~
ls/usr/bin/../include/c++/v1/type_traits:2422:12: error: call to implicitly-deleted copy constructor of 'typename
decay::type' (aka 'TestClass')
return _VSTD::forward<_Tp>(__t);
----------------------------------------------
#include <iostream>
#include <vector>
#include <queue>
#include <thread>
#include <condition_variable>
using namespace std;
class TestClass{
public:
void producer(int i) {
unique_lock<mutex> lockGuard(mtx);
Q.push(i);
lockGuard.unlock();
cond.notify_all();
}
void consumer() {
unique_lock<mutex> lockGuard(mtx);
cond.wait(lockGuard, [this]() {
return !Q.empty();
});
cout<<this_thread::get_id();
cout<<Q.front()<<endl;
Q.pop();
lockGuard.unlock();
};
private:
mutex mtx;
condition_variable cond;
queue<int> Q;
};
int main() {
std::cout << "Hello, World!" << std::endl;
int MAX_THREADS = std::thread::hardware_concurrency()-1;
vector<thread> ThreadVector;
TestClass testObj;
for(int i=0; i<MAX_THREADS; i++){
ThreadVector.emplace_back(&TestClass::consumer, std::move(testObj));
cout<<"Pool threadID:" <<ThreadVector[i].get_id()<<endl;
}
TestClass testObj2;
for(int i=0; i<10; i++) {
testObj.producer(i);
}
for(auto &&t : ThreadVector) {
t.join();
}
return 0;
}
`
Another version to call threads
int main()
{
std::vector<std::thread> vecOfThreads;
std::function<void(TestClass&)> func = [&](TestClass &obj) {
while(1) {
obj.consumer();
}
};
unsigned MAX_THREADS = std::thread::hardware_concurrency()-1;
TestClass obj;
for(int i=0; i<MAX_THREADS; i++) {
std::thread th1(func, std::ref(obj));
vecOfThreads.emplace_back(std::move(th1));
}
TestClass prod;
for(int i=0; i<10; i++) {
prod.producer(i);
}
for (std::thread & th : vecOfThreads)
{
if (th.joinable())
th.join();
}
return 0;
}

std::move(testObj) should be &testObj (a pointer to the object to call consumer on) - or std::ref(testobj) (which becomes a reference_wrapper (holding a pointer to the object too).
You should call produce at least as many times as you have threads, or else the program won't finish.
You don't need to unlock manually. The guards unlock automatically when they go out of scope.
Example:
class TestClass {
public:
void producer(int i) {
lock_guard<mutex> lockGuard(mtx); // here a lock_guard is enough
Q.push(i);
// no manual unlocking
cond.notify_all();
}
void consumer() {
unique_lock<mutex> lockGuard(mtx);
cond.wait(lockGuard, [this] { return !Q.empty(); });
cout << this_thread::get_id();
cout << Q.front() << endl;
Q.pop();
};
private:
mutex mtx;
condition_variable cond;
queue<int> Q;
};
int main() {
std::cout << "Hello, World!" << std::endl;
unsigned MAX_THREADS = std::thread::hardware_concurrency() - 1;
vector<thread> ThreadVector;
ThreadVector.reserve(MAX_THREADS); // since you know how many, reserve
TestClass testObj;
for(unsigned i = 0; i < MAX_THREADS; i++) {
// here, &testobj
ThreadVector.emplace_back(&TestClass::consumer, &testObj);
cout << "Pool threadID:" << ThreadVector[i].get_id() << endl;
}
// produce MAX_THREADS of things to put in the queue:
for(int i = 0; i < MAX_THREADS; i++) {
testObj.producer(i);
}
for(auto&& t : ThreadVector) {
t.join();
}
}
Regarding your questions in the comment section: If you'd like to keep the consumer threads running until you tell them to quit, you could add another variable (called run here) that the consumer threads monitor.
Example:
#include <condition_variable>
#include <iostream>
#include <queue>
#include <thread>
#include <vector>
using namespace std;
class TestClass {
public:
void producer(int i) {
lock_guard<mutex> lockGuard(mtx);
Q.push(i);
to_pool.notify_one();
}
void consumer() {
while(true) {
unique_lock<mutex> lockGuard(mtx);
to_pool.wait(lockGuard, [this] { return !run || !Q.empty(); });
if(!run) break; // time to quit
cout << this_thread::get_id() << ' ' << Q.front() << endl;
Q.pop();
// Tell producer that we picked one from the queue.
// if it's only interesting to notify when the queue is empty,
// add: if(Q.empty())
to_producer.notify_one();
}
};
void stop() {
lock_guard<mutex> lockGuard(mtx);
run = false; // tell all pool threads to quit
to_pool.notify_all();
}
void wait_for_all_work_to_be_done() {
std::unique_lock<mutex> lg(mtx);
to_producer.wait(lg, [this] { return Q.empty(); });
}
private:
bool run = true;
mutex mtx;
condition_variable to_pool;
condition_variable to_producer;
queue<int> Q;
};
int main() {
std::cout << "Hello, World!" << std::endl;
unsigned MAX_THREADS = std::thread::hardware_concurrency() - 1;
vector<thread> ThreadVector;
ThreadVector.reserve(MAX_THREADS);
TestClass testObj;
for(unsigned i = 0; i < MAX_THREADS; i++) {
ThreadVector.emplace_back(&TestClass::consumer, &testObj);
cout << "Pool threadID:" << ThreadVector[i].get_id() << endl;
}
for(int i = 0; i < MAX_THREADS / 2; i++) {
testObj.producer(i);
}
testObj.wait_for_all_work_to_be_done();
// stop pool threads
testObj.stop();
for(auto&& t : ThreadVector) t.join();
}

Related

C++ Multiple consumer threads stuck on condition variable

I'm making a single producer, multiple consumers program in C++. I begin by calling consumer threads and then I add elements to an array.
Everything works fine, but in the end the consumer threads are not joining, because they're stuck waiting on condition variable and the program freezes.
I think the problem is that threads are constantly called in the loop because currentSize is not protected and they just can't exit out of the condition variable, but I don't know how to fix it.
struct Item {
public:
string name;
int time;
double height;
};
struct Monitor {
private:
Item items[12];
int currentSize;
bool finished;
mutex lock;
condition_variable cv;
public:
Monitor() {
finished = false;
currentSize = 0;
}
void put(Item item) {
unique_lock<mutex> guard(lock);
cv.wait(guard, [&] { return (currentSize < 12); });
items[currentSize] = item;
currentSize++;
cv.notify_all();
}
Item get() {
unique_lock<mutex> guard(lock);
cv.wait(guard, [&] { return (currentSize > 0); });
Item item = items[currentSize - 1];
currentSize--;
return item;
}
bool get_finished() {
return finished;
}
void set_finished() {
finished = true;
}
int get_size() {
return currentSize;
}
};
int main() {
vector<Item> items = read_file(file);
Monitor monitor;
vector<thread> threads;
vector<Item> results;
for (int i = 0; i < 4; i++) {
threads.emplace_back([&] {
while (!monitor.get_finished()) {
if (monitor.get_size() > 0) {
Item item = monitor.get();
results.push_back(item);
}
}
});
}
for (int i = 0; i < items.size(); i++) {
monitor.put(items[i]);
}
monitor.set_finished();
for_each(threads.begin(), threads.end(), mem_fn(&thread::join));
return 0;
}
Why the consumer threads block?
I have tested your code, and it turns out to be the producer thread blocking on the put() method. Why?
Imagine the following scenario: there are 13 items in the vector items.
The main thread (producer) happily loads the first 12 items, and waits on cv for the currentSize to become lower than 12.
The consumer threads are notified, and happily consume the first 12 items, and then wait on cv for currentSize to become greater than 0.
But wait! Now everyone is waiting on something, with no one notifying. Thus, all threads would block. You need to notify the producer when currentSize becomes lower than 12.
I noticed a few issues. made the member variables atomic, notify_all in get api. However there was al logic error as well. Imagine that you have 4 threads currently running and 5 items were in queue. At this point lets say each of the thread is able to get one out of the queue and now there are 4 threads and only one item in the queue. One of the thread takes the last one out and now there is 0 items in there however other three threads still waiting on the condition variable. So a solution is if the last item is out everythread should be notified and if there is no other elemnet get back from the API.
#include <iostream>
#include <vector>
#include <condition_variable>
#include <thread>
#include <algorithm>
#include <atomic>
using namespace std;
using Item = int;
struct Monitor {
private:
Item items[12];
std::atomic<int> currentSize;
std::atomic<bool> finished;
mutex lock;
condition_variable cv;
public:
Monitor() {
finished = false;
currentSize = 0;
}
void put(Item item) {
unique_lock<mutex> guard(lock);
cv.wait(guard, [&] { return (currentSize < 12); });
items[currentSize] = item;
currentSize++;
cv.notify_all();
std::cerr << "+ " << currentSize << std::endl ;
}
Item get() {
unique_lock<mutex> guard(lock);
cv.wait(guard, [&] { return (currentSize >= 0 ); });
Item item;
if (currentSize > 0 ){
currentSize--;
item = items[currentSize];
cv.notify_all();
std::cerr << "- " << currentSize << std::endl ;
}
return item;
}
bool get_finished() {
return finished;
}
void set_finished() {
finished = true;
}
int get_size() {
return currentSize;
}
};
int main() {
vector<Item> items(200);
std::fill ( items.begin() , items.end(), 100);
Monitor monitor;
vector<thread> threads;
vector<Item> results;
for (int i = 0; i < 10; i++) {
threads.emplace_back([&] {
while ( !monitor.get_finished() ) {
if (monitor.get_size() > 0) {
Item item = monitor.get();
results.push_back(item);
}
}
});
}
for (int i = 0; i < items.size(); i++) {
monitor.put(items[i]);
}
monitor.set_finished();
for_each(threads.begin(), threads.end(), mem_fn(&thread::join));
return 0;
}

Why program works correctly while join only 1 thread but there are 5

This is my code and I accidentally made a mistake buy not making the for loop longer but the code works as intended.
What happens after the program is completed? Does it have any fail cases or does the computer auto kill all thread and if there would be any additional code it Threads again would there be problems( for example if i would initiate 2 thread then there would be 6 thread working and the new thread ids would be 5 and 7?)
#include <iomanip>
#include <thread>
#include <iostream>
#include <mutex>
#include <sstream>
#include <vector>
#include <conio.h>
using namespace std;
bool endProgram = false;
struct Monitorius {
public:
int IOCounter = 0;
int readCounterC = 0;
int readCounterD = 0;
condition_variable cv;
mutex mtx;
int c = 10;
int d = 100;
Monitorius() {
c = 10;
d = 100;
IOCounter = 0;
readCounterC = 0;
readCounterD = 0;
}
void changeC(int i) {
while (!endProgram) {
unique_lock<mutex> lck(mtx);
cv.wait(lck, [&] {return readCounterC > 1; });
if (!endProgram) {
c += i;
readCounterC = 0;
cv.notify_all();
}
}
}
void changeD(int i) {
while (!endProgram) {
unique_lock<mutex> lck(mtx);
cv.wait(lck, [&] {return readCounterD > 1; });
if (!endProgram) {
d -= i;
readCounterD = 0;
cv.notify_all();
}
}
}
void readCD(int i) {
int oldC = -1;
int oldD = -1;
while (!endProgram) {
unique_lock<mutex> lck(mtx);
cv.wait(lck, [&] {return oldC != c && oldD != d; });
if (!endProgram) {
stringstream str;
str << i << ": c:" << c << " d: " << d << endl;
cout << str.str();
readCounterC++;
readCounterD++;
IOCounter++;
if (IOCounter >= 15)
endProgram = true;
cv.notify_all();
oldC = c;
oldD = d;
}
}
}
};
int main()
{
Monitorius M;
vector<thread> myThreads;
myThreads.reserve(5);
myThreads.emplace_back([&] { M.changeC(1); });
myThreads.emplace_back([&] { M.changeD(2); });
myThreads.emplace_back([&] { M.readCD(3); });
myThreads.emplace_back([&] { M.readCD(4); });
myThreads.emplace_back([&] { M.readCD(5); });
for (size_t i = 0; i < 1; i++)
myThreads[i].join();
_getch();
}
When your main function exits, all the threads in the vector will be destructed.
If they are not joined at that time std::terminate should be called by the std::thread destructor.
By detaching threads the thread-objects can be destructed and the thread still continues to run. But then on the common modern operating systems when the process ends (which happens after main have returned or exit is called) the threads will be killed anyway. To let threads continue running even after the "main" thread ends, you have to call a system-dependent function to exit the "main" thread.
I do not know if it's possible to do this on Windows though, as the ExitThread function should not be used by C++ code as it exits the thread without destructing objects.
The solution to both problems is of course to properly join all threads.

When I use thread and mutex, C++ occur Memory leak

I want store integer to write_odd_queue, then popping integer from another thread.
data_prepation_thread function will store integer to write_odd_queue.
handle_odd function will pop integer from write_odd_queue.
When I write Sleep(10), memory will not increase.
When I comment this code, memory will increase.
Please help me solve this problem.
#include <iostream>
#include <vector>
#include <thread>
#include <random>
#include <windows.h>
#include <time.h>
#include <mutex>
#include <queue>
#include <condition_variable>
using namespace std;
queue<int> write_odd_queue;
mutex write_odd_mutux;
void handle_odd()
{
while (true)
{
int i;
{
lock_guard<mutex> lk(write_odd_mutux);
if (!write_odd_queue.empty())
{
i = write_odd_queue.front();
write_odd_queue.pop();
cout << "test size " << write_odd_queue.empty() << " ";
}
else
{
continue;
}
}
cout << "odd " << i << endl;
Sleep(500);
}
}
void data_prepation_thread()
{
int i = 0;
while (true)
{
i++;
unique_lock<mutex> lk(write_odd_mutux);
write_odd_queue.push(i);
lk.unlock();
// comment Sleep(10), memory will not increase.
//Sleep(10);
}
}
int main()
{
vector<thread> vec;
thread t1(handle_odd);
vec.push_back(move(t1));
data_prepation_thread();
auto it = vec.begin();
for (; it != vec.end(); ++it)
{
it->join();
}
return 0;
}
You are removing things from the queue with a delay of 500 milliseconds, and pushing them on to the queue with no delay - this means the queue will grow, as the frequency of your pops is not matching that of your pushes. Adding a delay to the pushes will reduce the growth, so that it may not be obvious for short runs of the program.
This is solution to avoid Sleep() in both functions using condition variables:
queue<int> write_odd_queue;
mutex write_odd_mutux;
condition_variable data_ready;
condition_variable queue_ready;
bool stopped = false;
const size_t max_size = 1024;
const size_t min_size = 512;
void handle_odd()
{
unique_lock<mutex> lk(write_odd_mutux);
while (!stopped)
{
if( write_odd_queue.empty() ) {
data_ready.wait( lk );
continue;
}
int i = write_odd_queue.front();
write_odd_queue.pop();
if( write_odd_queue.size() == min_size )
queue_ready.notify_one();
cout << "test size " << write_odd_queue.empty() << " ";
lk.unlock();
cout << "odd " << i << endl;
lk.lock();
}
}
void data_prepation_thread()
{
int i = 0;
while (!stopped)
{
unique_lock<mutex> lk(write_odd_mutux);
if( write_odd_queue.size() >= max_size ) {
queue_ready.wait( lk );
continue;
}
write_odd_queue.push(++i);
if( write_odd_queue.size() == 1 )
data_ready.notify_all();
}
}
void stop()
{
unique_lock<mutex> lk(write_odd_mutux);
stopped = true;
data_ready.notify_all();
queue_ready.notify_all();
}
This will prevent queue to grow bigger than max_size and reenable pushing when size drops to min_size. Also there is no unnecessary delay in processing would be involved, as you would have with Sleep(500).

why introducing sleep causes producer consumer to wait?

I'm just learning to use the C++ threading library.
If anyone is curious - my code is just a modified version in a tutorial https://www.youtube.com/watch?v=13dFggo4t_I&t=6m45s
I wrote a simple producer/consumer code. I tried to introduce a sleep to make the producer and consumer in lockstep fashion, so item is consumed as soon as it is produced. But making the producer waits causes some deadlock. I couldn't figure out why.
Can you please help me point out what I'm missing in the code?
#include <iostream>
#include <thread>
#include <mutex>
#include <vector>
#include <chrono>
#define BUFFER_SIZE 10
std::mutex mu;
std::condition_variable full,empty;
std::vector<int> vec;
int i=0;
std::chrono::milliseconds slp(10);
void produce()
{
while (i < 2*BUFFER_SIZE) {
std::unique_lock<std::mutex> locker(mu);
full.wait(locker, [] {return vec.size() != BUFFER_SIZE;});
vec.push_back(i++);
empty.notify_one();
//std::this_thread::sleep_for(slp); <--- introducing this causes program to hang.
}
}
void consume()
{
while(!vec.empty()) {
std::unique_lock<std::mutex> locker(mu);
empty.wait(locker, [] {return !vec.empty();});
std::cout << "Consumed:" << vec.back() <<"\n";
vec.pop_back();
full.notify_one();
}
}
int main() {
vec.reserve(BUFFER_SIZE*2);
std::thread producer(produce), consumer(consume);
producer.join();
consumer.join();
return 0;
}
EDIT:
void produce()
{
while (i < 2*BUFFER_SIZE) {
std::unique_lock<std::mutex> locker(mu);
full.wait(locker, [] {return vec.size() != BUFFER_SIZE;});
vec.push_back(i++);
locker.unlock();
empty.notify_one();
std::this_thread::sleep_for(slp);
}
}
void consume()
{
while(!vec.empty()) {
std::unique_lock<std::mutex> locker(mu);
empty.wait(locker, [] {return !vec.empty();});
std::cout << "Consumed:" << vec.back() <<"\n";
vec.pop_back();
locker.unlock();
full.notify_one();
}
}
You have a couple of problems:
The consumer is accessing vec without the mutex held:
while(!vec.empty()) {
This is easily addressed by ensuring that all acceses to vec are "inside" the mutex.
If the consumer gets ahead of the producer and manages to empty vec, it will exit early. You can fix this by using some other mechanism to indicate completion.
You are performing some processing/io/sleep with the mutex held, reducing possible concurrency. ideally you should only hold the mutex while accessing shared state.
const unsigned BUFFER_SIZE = 10;
std::mutex mu;
std::condition_variable full,empty;
std::vector<int> vec;
const std::chrono::milliseconds slp(10);
auto done = false;
void produce()
{
for (auto i = 0u; i < 2 * BUFFER_SIZE; ++i) {
std::unique_lock<std::mutex> locker(mu);
full.wait(locker, [] {return vec.size() < BUFFER_SIZE;});
auto was_empty = vec.empty();
vec.push_back(i);
locker.unlock();
// Only notify if the buffer was empty before the push_back
if (was_empty) {
empty.notify_all();
}
std::this_thread::sleep_for(slp);
}
}
void consume()
{
for (;;) {
std::unique_lock<std::mutex> locker(mu);
while (vec.empty()) {
if (done) {
return;
}
empty.wait(locker);
}
auto was_full = vec.size() >= BUFFER_SIZE;
auto value = vec.back();
vec.pop_back();
locker.unlock();
if (was_full) {
full.notify_all();
}
std::cout << "Consumed: " << value << '\n';
}
}
int main() {
vec.reserve(BUFFER_SIZE*2);
std::thread producer(produce), consumer(consume);
producer.join();
// Produce some more
producer = std::thread(produce);
producer.join();
// Produce A LOT more
std::vector<std::thread> many_producers(8);
for (auto&& t : many_producers) {
t = std::thread(produce);
}
for (auto && t : many_producers) {
t.join();
}
// Tell consumer we are done producing
{
std::lock_guard<std::mutex> lock(mu);
done = true;
}
empty.notify_one();
consumer.join();
}
See it live at Coliru.

printing odd and even number printing alternately using threads in C++

Odd even number printing using thread I came across this question and wanted to discuss solution in C++ . What I can think of using 2 binary semaphores odd and even semaphore. even semaphore initialized to 1 and odd initialized to 0.
**T1 thread function**
funOdd()
{
wait(even)
print odd;
signal(odd)
}
**T2 thread function**
funEven()
{
wait(odd)
print even
signal(even)
}
In addition to this if my functions are generating only number and there is a third thread T3 which is going to print those numbers then what should be ideal design ? I used an array where odd number will be placed at odd place and even number will be place at even position. T3 will read from this array this will avoid any thread saftey over this array and if T3 does not find any index then it will wait till that index gets populated. Another solution can be to use a queue which will have a mutex which can be used by T1 and T2 while insertion.
Please comment on this solution and how can i make it more efficient.
Edit to make problem much clear: Overall problem is that I have two producers (T1,T2) and a single consumer (T3), and my producers are interdependent.
Using condition_variable
#include <iostream>
#include <thread>
#include <mutex>
#include <condition_variable>
std::mutex mu;
std::condition_variable cond;
int count = 1;
void PrintOdd()
{
for(; count < 100;)
{
std::unique_lock<std::mutex> locker(mu);
cond.wait(locker,[](){ return (count%2 == 1); });
std::cout << "From Odd: " << count << std::endl;
count++;
locker.unlock();
cond.notify_all();
}
}
void PrintEven()
{
for(; count < 100;)
{
std::unique_lock<std::mutex> locker(mu);
cond.wait(locker,[](){ return (count%2 == 0); });
std::cout << "From Even: " << count << std::endl;
count++;
locker.unlock();
cond.notify_all();
}
}
int main()
{
std::thread t1(PrintOdd);
std::thread t2(PrintEven);
t1.join();
t2.join();
return 0;
}
Solution using condition variable.
#include<iostream>
#include<thread>
#include<mutex>
using namespace std;
mutex oddevenMu;
condition_variable condVar;
int number = 1;
void printEvenOdd(bool isEven, int maxnubmer)
{
unique_lock<mutex> ul(oddevenMu);
while (number < maxnubmer)
{
condVar.wait(ul, [&]() {return number % 2 == isEven;});
cout << number++ << " ";
condVar.notify_all();
}
}
int main(string args[])
{
thread oddThread(printEvenOdd, false, 100);
thread evenThread(printEvenOdd, true, 100);
oddThread.join();
evenThread.join();
return 0;
}
#include <stdio.h>
#include <stdlib.h>
#include <iostream>
#include <pthread.h>
#include <semaphore.h>
sem_t sem;
sem_t sem2;
using namespace std ;
int count = 1;
void increment(int x)
{
cout << "called by thread : " << x << "count is : " << count ++ << "\n";
}
void *printAltmessage1(void *thread_value)
{
for(int m=0; m < (*(int *)thread_value); m++)
{
if (sem_wait(&sem) == 0)
{
cout << " Thread printAltmessage1 is executed" <<"\n";
increment(1);
sem_post(&sem2);
}
}
}
void *printAltmessage2(void *thread_value)
{
for(int m=0; m < (*(int *)thread_value); m++)
{
if (sem_wait(&sem2) == 0)
{
cout << " Thread printAltmessage2 is executed" <<"\n";
increment(2);
sem_post(&sem);
}
}
}
int main()
{
sem_init(&sem,0, 1);
sem_init(&sem2,0, 0);
pthread_t threads[2];
int x =8;
for(int i=0;i<2;i++)
{
if(i==0)
int rc =pthread_create(&threads[i],NULL,printAltmessage1,(void*)&x);
else
int rc =pthread_create(&threads[i],NULL,printAltmessage2,(void*)&x);
}
pthread_exit(NULL);
return 0;
}
This is the easiest solution you can refer:
#include<iostream>
#include<mutex>
#include<pthread.h>
#include<cstdlib>
int count=0;
using namespace std;
mutex m;
void* printEven(void *a)
{
while(1)
{
m.lock();
if(count%2==0)
{
cout<<" I am Even"<<count<<endl;
count++;
}
if(count==100)
break;
m.unlock();
}
}
void* printOdd(void *b)
{
while(1)
{
m.lock();
if(count%2!=0)
{
cout<<"I am odd"<<count<<endl;
count++;
}
if(count>100)
break;
m.unlock();
}
}
int main()
{
int *ptr = new int();
pthread_t thread1, thread2;
pthread_attr_t attr;
pthread_attr_init(&attr);
pthread_create(&thread1,&attr,&printEven,NULL);
pthread_create(&thread2,&attr,&printOdd, NULL);
pthread_join(thread1,&ptr);
pthread_join(thread2,&ptr);
delete ptr;
}
This is simple solution using single function.
#include <iostream>
#include <thread>
#include <condition_variable>
using namespace std;
mutex mu;
condition_variable cond;
int count = 1;
void PrintOddAndEven(bool even, int n){
while(count < n){
unique_lock<mutex> lk(mu);
cond.wait(lk, [&](){return count%2 == even;});
cout << count++ << " ";
lk.unlock();
cond.notify_all();
}
}
int main() {
int n = 10;
thread t1(PrintOddAndEven, true, n);
thread t2(PrintOddAndEven, false, n);
t1.join();
t2.join();
return 0;
}
#include <iostream>
#include <thread>
#include <mutex>
using namespace std;
std::mutex m;
int count = 0;
void printEven()
{
cout << "Entered Even\n" << endl;
while(count <= 10)
{
m.lock();
if(count%2 == 0)
cout << count++ << " ";
m.unlock();
}
}
void printOdd()
{
cout << "Entered Odd" << endl;
while(count < 10)
{
m.lock();
if(count%2 == 1)
cout << count++ << " ";
m.unlock();
}
}
int main()
{
std::thread t1(printOdd);
std::thread t2(printEven);
t1.join();
t2.join();
return 0;
}
#include "threadFunc.hpp"
#include <iostream>
#include <thread>
#include <mutex>
#include <condition_variable>
using namespace std;
mutex t1;
condition_variable cond;
int number = 11;
int count = 0;
void printEven()
{
while(1)
{
unique_lock<mutex> ul(t1);
if(count< number)
{
if(count % 2 != 0)
{
cond.wait(ul);
}
cout<<count<<" : printed by thread"<<this_thread::get_id()<<endl;
count++;
}
if(count > number)
break;
ul.unlock();
cond.notify_all();
}
}
void printOdd()
{
while(1)
{
unique_lock<mutex> ul(t1);
if(count< number)
{
if(count % 2 == 0)
{
cond.wait(ul);
}
cout<<count<<" : printed by thread"<<this_thread::get_id()<<endl;
count++;
}
if(count > number)
break;
ul.unlock();
cond.notify_all();
}
}
I fail to understand why you want to use three separate threads for a serial behavior. But I will answer anyway:)
One solution would be to use a modified producer/consumer pattern with a prioritized queue between producers and consumers. The sort operation on the queue would depend on the integer value of the posted message. The consumer would peek an element in the queue and check if it is the next expected element. If not, it would sleep/wait.
A bit of code:
class Elt implements Comparable<Elt> {
int value;
Elt(value) { this.value=value; }
int compare(Elt elt);
}
class EltQueue extends PriorityBlockingQueue<Elt> { // you shouldn't inherit colelctions, has-a is better, but to make it short
static EltQueue getInstance(); // singleton pattern
}
class Consumer{
Elt prevElt = new Elt(-1);
void work()
{
Elt elt = EltQueue.getInstance().peek();
if (elt.getValue() == prevElt.getValue()+1)) {
EltQueue.getInstance().poll();
//do work on Elt
}
}
}
class Producer {
int n=0; // or 1!
void work() {
EltQueue.getInstance().put(new Elt(n+=2));
}
}
As a first thing, the two functions should a least contain a loop, (unless you just want a single number)
A more standard solution (which remaps your idea) is to have a global structure containing a a mutex, and two condition variables (odd and even) plus a return value, and another condition for the printing. than use a uique_lock to handle the synchronization.
IN PSEUDOCODE:
struct global_t
{
mutex mtx;
int value = {0};
condition_variable be_odd, be_even, print_it;
bool bye = {false};
global_t() { be_odd.notify(); }
} global;
void odd_generator()
{
int my_odd = 1;
for(;;)
{
unique_lock lock(global.mtx);
if(global.bye) return;
global.be_odd.wait(lock);
global_value = my_odd; my_odd+=2;
global.print_it.notify();
if(my_odd > 100) bye=true;
} //let RAII to manage wait states and unlocking
};
void even_generator()
{ /* same as odd, with inverted roles */ }
void printer()
{
for(;;)
{
unique_lock lock(global.mtx);
if(bye) return;
global.ptint_it.wait(lock);
std::cout << global.value << std::endl;
((global.value & 1)? global.be_even: global.be_odd).notify();
}
}
int main()
{
thread oddt(odd_generator), event(even_generator), printt(printer);
oddt.join(), event.join(), printer.join();
}
Note that, apart didactic purpose, this solution adds no value respect to a simple loop printing the value of a counter, since there will never be real concurrency.
Note also (to avoid globals) that you can wrap everything into a class (making the actual main a class method) and instantate that class on the stack inside the new main.
Solution is based on C++11 critical code section aka mutex.
Here's the working code, followed by an explanation.
Tested and working on VS2013:
using namespace std;
#include <iostream>
#include <string>
#include <thread>
#include <mutex>
std::mutex mtx;
void oddAndEven(int n, int end);
int main()
{
std::thread odd(oddAndEven, 1, 10);
std::thread Even(oddAndEven, 2, 10);
odd.join();
Even.join();
return 0;
}
void oddAndEven(int n, int end){
int x = n;
for (; x < end;){
mtx.lock();
std::cout << n << " - " << x << endl;
x += 2;
mtx.unlock();
std::this_thread::yield();
continue;
}
}
i.e:
Thread odd goes to method oddAndEven with starting number 1 thus he is the odd. He is the first to acquire the lock which is the mtx.lock().
Meanwhile, thread Even tries to acquire the lock too but thread odd acquired it first so thread Even waits.
Back to thread odd (which has the lock), he prints the number 1 and releases the lock with mtx.unlock(). At this moment, we want thread Even to acquire lock and to print 2 so we notify thread Even by writing std::this_thread::yield(). Then thread Even does the same.
etc etc etc.
#include <iostream>
#include <thread>
#include <mutex>
std::mutex mu;
unsigned int change = 0;
void printConsecutiveNumbers(int start, int end,unsigned int consecutive)
{
int x = start;
while (x < end)
{
//each thread has check there time is coming or not
if (change % consecutive == start)
{
std::unique_lock<std::mutex> locker(mu);
std::cout << "Thread " << start << " -> " << x << std::endl;
x += consecutive;
change++;
//to counter overflow
change %= consecutive;
}
}
}
int main()
{
//change num = 2 for printing odd and even
const int num = 7;
const int endValue = 1000;
std::thread threads[num];
//Create each consecutive threads
for (int i = 0; i < num; i++)
{
threads[i] = std::thread(printConsecutiveNumbers, i, endValue, num);
}
//Joins all thread to the main thread
for (int i = 0; i < num; i++)
{
threads[i].join();
}
return 0;
}
This code will work . I have tested it on visual studio 2017
#include "stdafx.h"
#include <iostream>
#include <mutex>
#include <thread>
#include <condition_variable>
using namespace std;
mutex m;
condition_variable cv;
int num = 1;
void oddThread() {​​​​​​​
for (; num < 10;) {​​​​​​​
unique_lock<mutex> lg(m);
cv.wait(lg, [] {​​​​​​​return (num % 2 ==1); }​​​​​​​);
cout << "From odd Thread " << num << endl;
num++;
lg.unlock();
cv.notify_one();
}​​​​​​​
}​​​​​​​
void evenThread() {​​​​​​​
for (; num < 100;) {​​​​​​​
unique_lock<mutex> lg(m);
cv.wait(lg, [] {​​​​​​​return (num % 2 == 0); }​​​​​​​);
cout << "From even Thread " << num << endl;
num++;
lg.unlock();
cv.notify_one();
}​​​​​​​
}​​​​​​​
int main() {​​​​​​​
thread t1{​​​​​​​ oddThread}​​​​​​​; //odd function thread
thread t2{​​​​​​​ evenThread}​​​​​​​;
t1.join();
t2.join();
cin.get();
return 0;
}​​​​​​​
output
from oddThread: 1
from evenThread: 2
from oddThread: 3
from evenThread: 4
from oddThread: 5
from evenThread: 6
from oddThread: 7
from evenThread: 8
from oddThread: 9
from evenThread: 10
#include <iostream>
#include <thread>
#include <mutex>
#include <condition_variable>
using namespace std;
std::mutex m;
std::condition_variable cv;
int counter =1;
void printEven()
{
std::unique_lock<std::mutex> lk(m);
while(1)
{
if(counter > 10)
break;
if(counter %2 != 0)
{
cv.wait (lk);
}
else
{
cout << "counter : " << counter << endl;
counter++;
//lk.unlock();
cv.notify_one();
}
}
}
void printOdd()
{
std::unique_lock<std::mutex> lk(m);
while(1)
{
if(counter > 9)
break;
if(counter %2 == 0)
{
cv.wait (lk);
}
else
{
cout << "counter : " << counter << endl;
counter++;
//lk.unlock();
cv.notify_one();
}
}
}
int main()
{
std::thread t1(printEven);
std::thread t2(printOdd);
t1.join();
t2.join();
cout << "Main Ends" << endl;
}
i have used anonymous func (lambda) to do this and clubbed cond variable and mutex.
#include <iostream>
#include <thread>
#include <condition_variable>
#include <mutex>
#include <chrono>
using namespace std;
int main() {
int count = 1;
mutex mtx;
condition_variable condition;
const int ITERATIONS = 20; // iterations
//prints odd numbers
thread t1([&]() {
while (count < ITERATIONS)
{
unique_lock <mutex> lock(mtx);
condition.wait(lock, [&]() {
return count % 2 != 0;
});
cout << "thread1 prints: " << count << endl;
count++;
lock.unlock();
condition.notify_all();
}
});
thread t2([&]
{
while (count < ITERATIONS)
{
unique_lock <mutex> lock(mtx);
condition.wait(lock, [&]() {
return count % 2 == 0;
});
cout << "thread2 prints: " << count << endl;
count++;
lock.unlock();
condition.notify_all();
}
});
t1.join();
t2.join();
}
#include <bits/stdc++.h>
#include <stdlib.h>
#include <unistd.h>
#include <thread>
#include <mutex>
#include <condition_variable>
using namespace std;
mutex m;
condition_variable cv;
unique_lock<mutex> lck(m);
void *printeven(void *arg)
{
int *n = (int *)arg;
while (*n <= 100)
{
cv.wait(lck);
*n = *((int *)arg);
cout << this_thread::get_id() << " : " << *n << endl;
*n = *n + 1;
cv.notify_one();
}
exit(0);
}
void *printodd(void *arg)
{
int *n = (int *)arg;
while (*n <= 100)
{
*n = *((int *)arg);
cout << this_thread::get_id() << " : " << *n << endl;
*n = *n + 1;
cv.notify_one();
cv.wait(lck);
}
exit(0);
}
int main()
{
int num = 1;
pthread_t p1 = 1;
pthread_t p2 = 2;
pthread_create(&p1, NULL, printodd, &num);
pthread_create(&p2, NULL, printeven, &num);
pthread_join(p1, NULL);
pthread_join(p2, NULL);
return 0;
}
#include <iostream>
#include <thread>
#include <mutex>
#include <condition_variable>
std::mutex mtx;
std::condition_variable even_to_odd;
std::condition_variable odd_to_even;
unsigned int count = 1;
constexpr int MAX_COUNT = 20;
void even(int n) {
for (int i = n; i <= MAX_COUNT; i++) {
std::unique_lock<std::mutex> lock(mtx);
if (i %2 == 0) {
odd_to_even.wait(lock);
std::cout << "Even: " << i << std::endl;
even_to_odd.notify_one();
}
}
}
void odd(int n) {
for (int i = n; i <= MAX_COUNT; i++) {
std::unique_lock<std::mutex> lock(mtx);
if (i == 1) {
std::cout << "Odd : " << i << std::endl;
odd_to_even.notify_one();
}
else if (i % 2 != 0) {
even_to_odd.wait(lock);
std::cout << "Odd : " << i << std::endl;
odd_to_even.notify_one();
}
}
}
int main() {
std::thread thread1(even,count);
std::thread thread2(odd,count);
thread1.join();
thread2.join();
return 0;
}
Please see below working code (VS2005)
#include <windows.h>
#include <stdlib.h>
#include <iostream>
#include <process.h>
#define MAX 100
int shared_value = 0;
CRITICAL_SECTION cs;
unsigned _stdcall even_thread_cs(void *p)
{
for( int i = 0 ; i < MAX ; i++ )
{
EnterCriticalSection(&cs);
if( shared_value % 2 == 0 )
{
printf("\n%d", i);
}
LeaveCriticalSection(&cs);
}
return 0;
}
unsigned _stdcall odd_thread_cs(void *p)
{
for( int i = 0 ; i < MAX ; i++ )
{
EnterCriticalSection(&cs);
if( shared_value % 2 != 0 )
{
printf("\n%d", i);
}
LeaveCriticalSection(&cs);
}
return 0;
}
int main(int argc, char* argv[])
{
InitializeCriticalSection(&cs);
_beginthreadex(NULL, NULL, even_thread_cs, 0,0, 0);
_beginthreadex(NULL, NULL, odd_thread_cs, 0,0, 0);
getchar();
return 0;
}
Here, using shared variable shared_value, we are synchronizing the even_thread_cs and odd_thread_cs.
Note that sleep is not used.