I am using C++11 on Mac OS Xcode 4.3.2
std::async uses same thread and my code does not achieve parallelism. In sample code below I want to create 10 new threads. In each thread I want to calculate square root of input variable and set the result in promise. in main function I want to display the results calculated from threads. I am calling std::async with policy launch::async, So I expect it to create a new thread(10 times).
#include <mutex>
#include <future>
#include <thread>
#include <vector>
#include <cmath>
#include <iostream>
using namespace std;
mutex iomutex;
void foo(int i, promise<double> &&prms)
{
this_thread::sleep_for(chrono::seconds(2));
prms.set_value(sqrt(i));
{
lock_guard<mutex> lg(iomutex);
cout << endl << "thread index=> " << i << ", id=> "<< this_thread::get_id();
}
}
int main()
{
{
lock_guard<mutex> lg(iomutex);
cout << endl << "main thread id=>"<< this_thread::get_id();
}
vector<future<double>> futureVec;
vector<promise<double>> prmsVec;
for (int i = 0; i < 10; ++i) {
promise<double> prms;
future<double> ftr = prms.get_future();
futureVec.push_back(move(ftr));
prmsVec.push_back(move(prms));
async(launch::async, foo, i, move(prmsVec[i]));
}
for (auto iter = futureVec.begin(); iter != futureVec.end(); ++iter) {
cout << endl << iter->get();
}
cout << endl << "done";
return 0;
}
However if I use std::thread, then I can achieve parallelism.
#include <mutex>
#include <future>
#include <thread>
#include <vector>
#include <cmath>
#include <iostream>
using namespace std;
mutex iomutex;
void foo(int i, promise<double> &&prms)
{
this_thread::sleep_for(chrono::seconds(2));
prms.set_value(sqrt(i));
{
lock_guard<mutex> lg(iomutex);
cout << endl << "thread index=> " << i << ", id=> "<< this_thread::get_id();
}
}
int main()
{
{
lock_guard<mutex> lg(iomutex);
cout << endl << "main thread id=>"<< this_thread::get_id();
}
vector<future<double>> futureVec;
vector<promise<double>> prmsVec;
vector<thread> thrdVec;
for (int i = 0; i < 10; ++i) {
promise<double> prms;
future<double> ftr = prms.get_future();
futureVec.push_back(move(ftr));
prmsVec.push_back(move(prms));
thread th(foo, i, move(prmsVec[i]));
thrdVec.push_back(move(th));
}
for (auto iter = futureVec.begin(); iter != futureVec.end(); ++iter) {
cout << endl << iter->get();
}
for (int i = 0; i < 10; ++i) {
thrdVec[i].join();
}
cout << endl << "done";
return 0;
}
async(launch::async, foo, i, move(prmsVec[i]));
This line returns a future but because you do not assign it to anything the future's destructor runs at the end of the statement, which blocks and waits for the result by calling std::future::wait()
Why are you manually calling std::async with a promise, when it returns a future anyway? The point of async is that you don't need to manually use a promise, that's done internally for you.
Rewrite your foo() to return double then call it with async
#include <mutex>
#include <future>
#include <thread>
#include <vector>
#include <cmath>
#include <iostream>
using namespace std;
mutex iomutex;
double foo(int i)
{
this_thread::sleep_for(chrono::seconds(2));
lock_guard<mutex> lg(iomutex);
cout << "\nthread index=> " << i << ", id=> "<< this_thread::get_id();
return sqrt(i);
}
int main()
{
cout << "\nmain thread id=>" << this_thread::get_id();
vector<future<double>> futureVec;
for (int i = 0; i < 10; ++i)
futureVec.push_back(async(launch::async, foo, i));
for (auto& fut : futureVec)
{
auto x = fut.get();
lock_guard<mutex> lg(iomutex);
cout << endl << x;
}
cout << "\ndone\n";
}
Related
I have some code which I'm working on where a detached thread is spawned, does some work, and then should wait for a signal from main() before sending another signal back to main indicating that the thread has quit.
I'm fairly new to condition variables, however I have worked with some multi thread code before. (Mostly mutexes.)
This is what I tried to implement, but it doesn't behave the way I would have expected. (Likely I misunderstood something.)
The idea behind this is to pass a struct containing two flags to each detached thread. The first flag indicates that main() says "it is ok to exit, and drop off the end of the thread function". The second flag is set by the thread itself and signals to main() that the thread has indeed exited. (It's just to confirm the signal from main() is recieved ok and to send something back.)
#include <cstdlib> // std::atoi
#include <iostream>
#include <thread>
#include <vector>
#include <random>
#include <future>
#include <condition_variable>
#include <mutex>
struct ThreadStruct
{
int id;
std::condition_variable cv;
std::mutex m;
int ok_to_exit;
int exit_confirm;
};
void Pause()
{
std::cout << "Press enter to continue" << std::endl;
std::cin.get();
}
void detachedThread(ThreadStruct* threadData)
{
std::cout << "START: Detached Thread " << threadData->id << std::endl;
// Performs some arbitrary amount of work.
for(int i = 0; i < 100000; ++ i);
std::cout << "FINISH: Detached thread " << threadData->id << std::endl;
std::unique_lock<std::mutex> lock(threadData->m);
std::cout << "WAIT: Detached thread " << threadData->id << std::endl;
threadData->cv.wait(lock, [threadData]{return threadData->ok_to_exit == 1;});
std::cout << "EXIT: Detached thread " << threadData->id << std::endl;
threadData->exit_confirm = 1;
}
int main(int argc, char** argv)
{
int totalThreadCount = 1;
ThreadStruct* perThreadData = new ThreadStruct[totalThreadCount];
std::cout << "Main thread starting " << totalThreadCount << " thread(s)" << std::endl;
for(int i = totalThreadCount - 1; i >= 0; --i)
{
perThreadData[i].id = i;
perThreadData[i].ok_to_exit = 0;
perThreadData[i].exit_confirm = 0;
std::thread t(detachedThread, &perThreadData[i]);
t.detach();
}
for(int i{0}; i < totalThreadCount; ++i)
{
ThreadStruct *threadData = &perThreadData[i];
std::cout << "Waiting for lock - main() thread" << std::endl;
std::unique_lock<std::mutex> lock(perThreadData[i].m);
std::cout << "Lock obtained - main() thread" << std::endl;
perThreadData[i].cv.wait(lock);
threadData->ok_to_exit = 1;
// added after comment from Sergey
threadData->cv.notify_all();
std::cout << "Done - main() thread" << std::endl;
}
for(int i{0}; i < totalThreadCount; ++i)
{
std::size_t thread_index = i;
ThreadStruct& threadData = perThreadData[thread_index];
std::unique_lock<std::mutex> lock(threadData.m);
std::cout << "i=" << i << std::endl;
int &exit_confirm = threadData.exit_confirm;
threadData.cv.wait(lock, [exit_confirm]{return exit_confirm == 1;});
std::cout << "i=" << i << " finished!" << std::endl;
}
Pause();
return 0;
}
This runs to the line:
WAIT: Detached thread 0
but the detached thread never quits. What have I done wrong?
Edit: Further experimentation - is this helpful?
I thought it might be helpful to simplify things by removing a step. In the example below, main() does not signal to the detached thread, it just waits for a signal from the detached thread.
But again, this code hangs - after printing DROP... This means the detached thread exits ok, but main() doesn't know about it.
#include <cstdlib> // std::atoi
#include <iostream>
#include <thread>
#include <vector>
#include <random>
#include <future>
#include <condition_variable>
#include <mutex>
struct ThreadStruct
{
int id;
std::condition_variable cv;
std::mutex m;
int ok_to_exit;
int exit_confirm;
};
void Pause()
{
std::cout << "Press enter to continue" << std::endl;
std::cin.get();
}
void detachedThread(ThreadStruct* threadData)
{
std::cout << "START: Detached Thread " << threadData->id << std::endl;
// Performs some arbitrary amount of work.
for(int i = 0; i < 100000; ++ i);
std::cout << "FINISH: Detached thread " << threadData->id << std::endl;
std::unique_lock<std::mutex> lock(threadData->m);
std::cout << "EXIT: Detached thread " << threadData->id << std::endl;
threadData->exit_confirm = 1;
threadData->cv.notify_all();
std::cout << "DROP" << std::endl;
}
int main(int argc, char** argv)
{
int totalThreadCount = 1;
ThreadStruct* perThreadData = new ThreadStruct[totalThreadCount];
std::cout << "Main thread starting " << totalThreadCount << " thread(s)" << std::endl;
for(int i = totalThreadCount - 1; i >= 0; --i)
{
perThreadData[i].id = i;
perThreadData[i].ok_to_exit = 0;
perThreadData[i].exit_confirm = 0;
std::thread t(detachedThread, &perThreadData[i]);
t.detach();
}
for(int i{0}; i < totalThreadCount; ++i)
{
std::size_t thread_index = i;
ThreadStruct& threadData = perThreadData[thread_index];
std::cout << "Waiting for mutex" << std::endl;
std::unique_lock<std::mutex> lock(threadData.m);
std::cout << "i=" << i << std::endl;
int &exit_confirm = threadData.exit_confirm;
threadData.cv.wait(lock, [exit_confirm]{return exit_confirm == 1;});
std::cout << "i=" << i << " finished!" << std::endl;
}
Pause();
return 0;
}
Your lambda is capturing by-value so it will never see the changes made to exit_confim.
Capture by-reference instead:
int& exit_confirm = threadData.exit_confirm;
threadData.cv.wait(lock, [&exit_confirm] { return exit_confirm == 1; });
// ^
// | capture by-reference
You also need to delete[] what you new[] so do
delete[] ThreadStruct;
when you're done with the the structs.
I also noticed some heap usage after free but that magically went away when I made some simplifications to the code. I didn't investigate that further.
Some suggestions:
Move code into the ThreadStruct class that deals with ThreadStruct member variables and locks. It usually makes it simpler to read and maintain.
Remove unused variables and headers.
Don't use new[]/delete[]. For this example, you could use a std::vector<ThreadStruct> instead.
Don't detach() at all - I haven't done anything about that below, but I suggest using join() (on attached threads) to do the final synchronization. That's what it's there for.
#include <condition_variable>
#include <iostream>
#include <mutex>
#include <thread>
#include <vector>
struct ThreadStruct {
int id;
// move this function into the ThreadStruct class
void detachedThread() {
std::cout << "START: Detached Thread " << id << std::endl;
// Performs some arbitrary amount of work (optimized away here)
std::cout << "FINISH: Detached thread " << id << std::endl;
std::lock_guard<std::mutex> lock(m);
std::cout << "EXIT: Detached thread " << id << std::endl;
exit_confirm = 1;
cv.notify_all();
std::cout << "DROP" << std::endl;
}
// add support functions instead of doing these things in your normal code
void wait_for_exit_confirm() {
std::unique_lock<std::mutex> lock(m);
cv.wait(lock, [this] { return exit_confirm == 1; });
}
void spawn_detached() {
std::thread(&ThreadStruct::detachedThread, this).detach();
}
private:
std::condition_variable cv;
std::mutex m;
int exit_confirm = 0; // initialize
};
With the above, main becomes a little cleaner:
int main() {
int totalThreadCount = 1;
std::vector<ThreadStruct> perThreadData(totalThreadCount);
std::cout << "Main thread starting " << perThreadData.size() << " thread(s)\n";
int i = 0;
for(auto& threadData : perThreadData) {
threadData.id = i++;
threadData.spawn_detached();
}
for(auto& threadData : perThreadData) {
std::cout << "Waiting for mutex" << std::endl;
std::cout << "i=" << threadData.id << std::endl;
threadData.wait_for_exit_confirm();
std::cout << "i=" << threadData.id << " finished!" << std::endl;
}
std::cout << "Press enter to continue" << std::endl;
std::cin.get();
}
For future interest: fixed the origional MWE posted in the question. There was two issues
not capturing local variable in lambda by reference (see other answer)
1 too many wait() calls
#include <cstdlib> // std::atoi
#include <iostream>
#include <thread>
#include <vector>
#include <random>
#include <future>
#include <condition_variable>
#include <mutex>
struct ThreadStruct
{
int id;
std::condition_variable cv;
std::mutex m;
int ok_to_exit;
int exit_confirm;
};
void Pause()
{
std::cout << "Press enter to continue" << std::endl;
std::cin.get();
}
void detachedThread(ThreadStruct* threadData)
{
std::cout << "START: Detached Thread " << threadData->id << std::endl;
// Performs some arbitrary amount of work.
for (int i = 0; i < 100000; ++i);
std::cout << "FINISH: Detached thread " << threadData->id << std::endl;
std::unique_lock<std::mutex> lock(threadData->m);
std::cout << "WAIT: Detached thread " << threadData->id << std::endl;
threadData->cv.wait(lock, [&threadData]{return threadData->ok_to_exit == 1;});
std::cout << "EXIT: Detached thread " << threadData->id << std::endl;
threadData->exit_confirm = 1;
threadData->cv.notify_all();
std::cout << "DROP" << std::endl;
}
int main(int argc, char** argv)
{
int totalThreadCount = 1;
ThreadStruct* perThreadData = new ThreadStruct[totalThreadCount];
std::cout << "Main thread starting " << totalThreadCount << " thread(s)" << std::endl;
for (int i = totalThreadCount - 1; i >= 0; --i)
{
perThreadData[i].id = i;
perThreadData[i].ok_to_exit = 0;
perThreadData[i].exit_confirm = 0;
std::thread t(detachedThread, &perThreadData[i]);
t.detach();
}
for(int i{0}; i < totalThreadCount; ++ i)
{
ThreadStruct *threadData = &perThreadData[i];
std::cout << "Waiting for lock - main() thread" << std::endl;
std::unique_lock<std::mutex> lock(perThreadData[i].m);
std::cout << "Lock obtained - main() thread" << std::endl;
//perThreadData[i].cv.wait(lock, [&threadData]{return threadData->ok_to_exit == 1;});
std::cout << "Wait complete" << std::endl;
threadData->ok_to_exit = 1;
threadData->cv.notify_all();
std::cout << "Done - main() thread" << std::endl;
}
for (int i{ 0 }; i < totalThreadCount; ++i)
{
std::size_t thread_index = i;
ThreadStruct& threadData = perThreadData[thread_index];
std::cout << "Waiting for mutex" << std::endl;
std::unique_lock<std::mutex> lock(threadData.m);
std::cout << "i=" << i << std::endl;
int& exit_confirm = threadData.exit_confirm;
threadData.cv.wait(lock, [&exit_confirm] {return exit_confirm == 1; });
std::cout << "i=" << i << " finished!" << std::endl;
}
Pause();
return 0;
}
I have a class called "Vector", which by default holds 10.000 elements, which at all times must have the same value. This class is tested and works. Therefore I use the method setAndTest() from the class to set the value of all elements, which then immediately checks whether the Vector object is consistent (that all vector elements hold the same value).
In a new file "main.cpp", i have created two functions: writer() and main().
writer() creates a user-defined number of writer threads (between 1 & 100), each with their own unique id. Each writer sets and tests the shared Vector object to its id every second. If a writer detects an inconsistensy in a shared Vector object, setAndTest() returns false and the following error message should be printed: Error with thread #id
However, in 99% of the cases it prints Success with thread #id, whereas I expected that there would be more variation between the two.
Headers included in main.cpp file:
#include <iostream>
#include "Vector.hpp"
#include <pthread.h>
#include <unistd.h>
using namespace std;
Vector object and writer() function:
Vector VecObj; //The Vector object (Defined in global scope)
void* writer(void *threadid)
{
int threadid_ = *(int *)(threadid);
if(VecObj.setAndTest(threadid_))
{
std::cout << "\nSuccess with thread " << threadid_ << endl;
}else
{
std::cout << "\nError with thread " << threadid_ << endl;
}
return NULL;
}
main function:
int main()
{
start:
int numOfThreads = 1;
std::cout << "Enter amount of threads (must be between 1 & 100): ";
std::cin >> numOfThreads;
if(0 < numOfThreads && numOfThreads <= 100){
std::cout << "You entered " << numOfThreads << " threads" << endl;
}else{
std::cout << "Amount of threads must be between 1 & 100" << endl;
goto start;
}
pthread_t threadcreator[numOfThreads];
for(int i = 0; i < numOfThreads; i++){
pthread_create(&threadcreator[i], NULL, writer, &i);
sleep(1);
}
for(int i = 0; i < numOfThreads; i++){
pthread_join(threadcreator[i], NULL);
}
}
Vector Class (Vector.hpp):
#ifndef VECTOR_HPP_
#define VECTOR_HPP_
#include <pthread.h>
using namespace std;
//=======================================================
// Class: Vector
// contains a size_-size vector of integers.
// Use the function setAndTest to set all elements
// of the vector to a certain value and then test that
// the value is indeed correctly set
//=======================================================
class Vector
{
public:
Vector(unsigned int size = 10000) : size_(size)
{
vector_ = new int[size_];
set(0);
}
~Vector()
{
delete[] vector_;
}
bool setAndTest(int n)
{
set(n);
return test(n);
}
private:
void set(int n)
{
for(unsigned int i=0; i<size_; i++) vector_[i] = n;
}
bool test(int n)
{
for(unsigned int i=0; i<size_; i++) if(vector_[i] != n) return false;
return true;
}
int* vector_;
unsigned int size_;
};
#endif
You are passing each thread a pointer to the same int variable. That variable changes value on each loop iteration. writer() is expecting to receive the same int value that was given to pthread_create(), but that is not guaranteed in your code, even with the sleep() call.
To pass the int correctly, pass the actual int value itself rather than a pointer to the int, eg:
#include <iostream>
#include <vector>
#include <cstdint>
#include <pthread.h>
#include "Vector.hpp"
Vector VecObj;
void* writer(void *arg)
{
int threadid_ = static_cast<int>(reinterpret_cast<intptr_t>(arg));
if (VecObj.setAndTest(threadid_))
{
std::cout << "\nSuccess with thread " << threadid_ << std::endl;
}
else
{
std::cout << "\nError with thread " << threadid_ << std::endl;
}
return NULL;
}
int main()
{
int numOfThreads = 0;
do {
std::cout << "Enter amount of threads (must be between 1 & 100): ";
std::cin >> numOfThreads;
if (0 < numOfThreads && numOfThreads <= 100){
std::cout << "You entered " << numOfThreads << " threads" << std::endl;
break;
}
std::cout << "Amount of threads must be between 1 & 100" << std::endl;
}
while (true);
std::vector<pthread_t> threadcreator(numOfThreads);
for(int i = 0; i < numOfThreads; i++){
pthread_create(&threadcreator[i], NULL, writer, reinterpret_cast<void*>(i));
}
for(int i = 0; i < numOfThreads; i++){
pthread_join(threadcreator[i], NULL);
}
return 0;
}
If you really want to use int* pointers, then you will have to allocate a separate int for each thread, eg:
#include <iostream>
#include <vector>
#include <pthread.h>
#include "Vector.hpp"
Vector VecObj;
void* writer(void *arg)
{
int threadid_ = *static_cast<int*>(arg);
if (VecObj.setAndTest(threadid_))
{
std::cout << "\nSuccess with thread " << threadid_ << std::endl;
}
else
{
std::cout << "\nError with thread " << threadid_ << std::endl;
}
return NULL;
}
int main()
{
int numOfThreads = 0;
do {
std::cout << "Enter amount of threads (must be between 1 & 100): ";
std::cin >> numOfThreads;
if (0 < numOfThreads && numOfThreads <= 100){
std::cout << "You entered " << numOfThreads << " threads" << std::endl;
break;
}
std::cout << "Amount of threads must be between 1 & 100" << std::endl;
}
while (true);
std::vector<pthread_t> threadcreator(numOfThreads);
std::vector<int> threadids(numOfThreads);
for(int i = 0; i < numOfThreads; i++){
threadids[i] = i;
pthread_create(&threadcreator[i], NULL, writer, &threadids[i]);
}
for(int i = 0; i < numOfThreads; i++){
pthread_join(threadcreator[i], NULL);
}
return 0;
}
Or, if you really want to pass an int* pointer to a single int, use a std::conditional_variable or other waitable signal to make sure that each thread has actually captured the int value before allowing the loop to change its value, eg:
#include <iostream>
#include <vector>
#include <conditional_variable>
#include <mutex>
#include "Vector.hpp"
#include <pthread.h>
Vector VecObj;
std::condition_variable cv;
std::mutex cv_m;
bool captured = false;
void* writer(void *arg)
{
int threadid_;
{
std::lock_guard<std::mutex> lk(cv_m);
threadid_ = *static_cast<int*>(arg);
captured = true;
}
cv.notify_one();
if (VecObj.setAndTest(threadid_))
{
std::cout << "\nSuccess with thread " << threadid_ << std::endl;
}
else
{
std::cout << "\nError with thread " << threadid_ << std::endl;
}
return NULL;
}
int main()
{
int numOfThreads = 0;
do {
std::cout << "Enter amount of threads (must be between 1 & 100): ";
std::cin >> numOfThreads;
if (0 < numOfThreads && numOfThreads <= 100){
std::cout << "You entered " << numOfThreads << " threads" << std::endl;
break;
}
std::cout << "Amount of threads must be between 1 & 100" << std::endl;
}
while (true);
std::vector<pthread_t> threadcreator(numOfThreads);
for(int i = 0; i < numOfThreads; i++){
std::unique_lock<std::mutex> lk(cv_m);
captured = false;
pthread_create(&threadcreator[i], NULL, writer, &i);
cv.wait(lk, [](){ return captured; });
}
for(int i = 0; i < numOfThreads; i++){
pthread_join(threadcreator[i], NULL);
}
return 0;
}
UPDATE: oh, now I see another major problem. You have multiple threads writing to, and reading from, a single Vector object in memory without synchronization. That is not safe to do. While one thread is reading from an element in the Vector's array, another thread can be writing a new value to that same element, and there is no guarantee that the element will remain consistent across both operations. You MUST synchronize access to the Vector object since it is being shared across multiple threads, eg:
...
#include <mutex>
...
Vector VecObj;
std::mutex vec_m;
...
void* writer(void *threadid)
{
int threadid_ = ...;
bool testResult;
{
std::lock_guard lk(vec_m);
testResult = VecObj.setAndTest(threadid_);
}
if (testResult)
{
std::cout << "\nSuccess with thread " << threadid_ << std::endl;
}
else
{
std::cout << "\nError with thread " << threadid_ << std::endl;
}
return NULL;
}
...
I want to make a program which displays current time that ticks in background then is it possible to initialize cin input processes while it is ticking?
just for fun:
#include <iostream>
#include <chrono>
#include <thread>
#include <atomic>
#include <mutex>
#include <ctime>
std::mutex more_lock;
std::string more_output;
void set_more_output(const std::string& more)
{
std::lock_guard<std::mutex> lock(more_lock);
more_output = more;
}
std::string get_more_output()
{
std::lock_guard<std::mutex> lock(more_lock);
return more_output;
}
std::atomic_bool running {true};
std::thread start_timer_runner()
{
return std::thread([&]{
while(running) {
using namespace std::chrono;
using namespace std::chrono_literals;
auto now = system_clock::to_time_t(system_clock::now());
auto now_str = std::string(std::ctime(&now));
now_str.pop_back(); // ctime adds new line
std::cout << "\r" << now_str << " | " << get_more_output() << std::flush;
std::this_thread::sleep_for(1s);
}
});
}
void parse_decimals()
{
int x;
set_more_output("please enter a decimal: ");
while(std::cin >> x)
{
set_more_output("thanks! you entered " + std::to_string(x) + ", please enter a new decimal: ");
}
}
int main()
{
auto timer = start_timer_runner();
parse_decimals();
running = false;
timer.join();
std::cout << std::endl << "bye bye!" << std::endl;
}
I've made a simple thread-safe Buffer implementation, creating 10 threads to work on the buffer queue to push and pop randomly some numbers. My implementation should let threads that are waiting to pop to wait only for 3 seconds and then terminate. When that occurs I print a timeout message.
The problem is that only one timeout message is printed, the main will then join all threads and return. Why?
Here is the code, main.cpp
#include <thread>
#include <vector>
#include <iostream>
#include <sstream>
#include "Buffer.h"
int main() {
std::vector<std::thread> workers;
Buffer<std::string> buffer(3);
srandom(time(NULL));
for (int i = 0; i < 10; i++) {
workers.emplace_back([&buffer]{
long num = random();
if(num%2==0) {
std::stringstream msg;
msg << std::this_thread::get_id() << " pushing " << num << std::endl;
std::cout << msg.str();
buffer.push(std::to_string(num));
} else {
std::stringstream msg1;
msg1 << std::this_thread::get_id() << " waiting to pop" << std::endl;
std::cout << msg1.str();
std::string popped_string = buffer.pop();
std::stringstream msg2;
msg2 << std::this_thread::get_id() << " popped " << popped_string << std::endl;
std::cout << msg2.str();
}
});
}
for (auto &w: workers) {
if (w.joinable()) w.join();
}
return 0;
}
Buffer.h
#ifndef PDS_CPP_BUFFER_H
#define PDS_CPP_BUFFER_H
#include <queue>
#include <mutex>
#include <condition_variable>
template <class T>
class Buffer {
private:
std::queue<T> queue;
std::mutex mutex;
std::condition_variable cv;
std::chrono::seconds sec;
public:
Buffer(int time) : sec(time), queue() {};
void push(T object) {
std::lock_guard lockGuard(mutex);
this->queue.push(object);
this->cv.notify_one();
}
T pop() {
std::unique_lock uniqueLock(mutex);
// this->cv.wait(uniqueLock, [this]{ return !this->queue.empty(); });
if(this->cv.wait_for(uniqueLock, this->sec, [this]{ return !this->queue.empty(); })) {
} else {
std::stringstream msg;
msg << std::this_thread::get_id() << " timeout" << std::endl;
std::cout << msg.str();
}
T object = this->queue.front();
this->queue.pop();
uniqueLock.unlock();
return object;
}
};
#endif //PDS_CPP_BUFFER_H
I have 4-threads in my program. I want to execute all of them once and once all of them are executed then only I want to enter the next iteration of execution.
I got a code on stack overflow that implements the boost::barrier function in C++. But it does not seem to work for me. For one iteration it works fine. But for the next iteration, the program execution just hangs.
//Here is my top code:
#include <iostream>
#include <stdio.h>
#include <thread>
#include "abc_func.hpp"
#include <vector>
using namespace std;
int main() {
abc obj1;
obj1.num_threads(4);
std::thread t1([&obj1](){
for (int i=0; i<5; i++) {
while (!obj1.abc_write(1));
};
});
std::thread t2([&obj1](){
for (int i=0; i<5; i++) {
while (!obj1.abc_read(2));
};
});
std::thread t3([&obj1](){
for (int i=0; i<5; i++) {
while (!obj1.abc_write(3));
};
});
std::thread t4([&obj1](){
for (int i=0; i<5; i++) {
while (!obj1.abc_read(4));
};
});
t1.join();
t2.join();
t3.join();
t4.join();
// cout << "done: " << obj1.done << endl;
// cout << "done: " << obj2.done << endl;
// cout << "wr_count: " << obj1.wr_count << endl;
return 0;
}
// Here is the abc_func.hpp
#include <iostream>
#include <stdio.h>
#include <thread>
#include <barrier.hpp>
using namespace std;
class abc {
size_t n_threads;
public:
abc() : n_threads(0) {};
void num_threads (size_t l) {
n_threads = l;
}
Barrier task_bar{n_threads};
bool abc_write (auto id) {
thread_local int wr_count = 0;
if (wr_count == 1) {
std::cout << "write thread waiting" << id << endl;
task_bar.Wait();
wr_count = 0;
};
std::cout << "write thread running " << id << endl;
++wr_count;
return true;
}
bool abc_read (auto id) {
thread_local int rd_count=0;
if (rd_count == 1) {
std::cout << "read thread waiting" << id << endl;
task_bar.Wait();
rd_count = 0;
};
std::cout << "read thread running " << id << endl;
++rd_count;
return true;
}
};
// and the barrier class code which I got on stack overflow
#include <thread>
#include <condition_variable>
#include <mutex>
#include <iostream>
#include <stdio.h>
class Barrier {
public:
explicit Barrier(std::size_t iCount) :
mThreshold(iCount),
mCount(iCount),
mGeneration(0) {
}
void Wait() {
std::unique_lock<std::mutex> lLock{mMutex};
auto lGen = mGeneration;
if (!--mCount) {
mGeneration++;
mCount = mThreshold;
mCond.notify_all();
} else {
mCond.wait(lLock, [this, lGen] { return lGen != mGeneration; });
}
}
private:
std::mutex mMutex;
std::condition_variable mCond;
std::size_t mThreshold;
std::size_t mCount;
std::size_t mGeneration;
};
The problem with this code is the member
Barrier task_bar{n_threads};
It is initialized once at the beginning while n_threads is 0. Later, when you call
obj1.num_threads(4);
the barrier object is not updated.
When you update the barrier as well, it works as expected
class Barrier {
public:
// ...
void num_threads(size_t n) {
mThreshold = n;
mCount = n;
}
// ...
};
and in abc::num_threads()
void num_threads (size_t l) {
n_threads = l;
task_bar.num_threads(l);
}