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);
}
Related
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'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 am trying to build an application which have multiple processes. These processes need to write concurrently through the same message queue. At the other side, there will be just one process reading that queue.
Is that possible using boost? Or do I have to implement that mutual exclusion?
I took a look at the example source code but it is not working properly for my needs. I don't know if I'm missing something.
This is the code on the client:
#include <boost/interprocess/ipc/message_queue.hpp>
#include <iostream>
#include <vector>
#include <unistd.h>
using namespace boost::interprocess;
int main ()
{
try{
//Erase previous message queue
//message_queue::remove("message_queue");
//Create a message_queue.
message_queue mq
(open_or_create //only create
,"message_queue" //name
,100 //max message number
,sizeof(int) //max message size
);
//Send 100 numbers
for(int i = 0; i < 100; ++i){
printf("Sending: %d\n", i);
usleep(1000000);
mq.send(&i, sizeof(i), 0);
}
}
catch(interprocess_exception &ex){
std::cout << ex.what() << std::endl;
return 1;
}
return 0;
}
And server code:
#include <boost/interprocess/ipc/message_queue.hpp>
#include <iostream>
#include <vector>
using namespace std;
using namespace boost::interprocess;
int main ()
{
try{
//message_queue::remove("message_queue");
//Open a message queue.
message_queue mq
(open_only //only create
,"message_queue" //name
);
unsigned int priority;
message_queue::size_type recvd_size;
//Receive 100 numbers
for(int i = 0; i < 100; ++i){
int number;
mq.receive(&number, sizeof(number), recvd_size, priority);
if(number != i || recvd_size != sizeof(number))
return 1;
cout << number << endl;
}
}
catch(interprocess_exception &ex){
message_queue::remove("message_queue");
std::cout << ex.what() << std::endl;
return 1;
}
//message_queue::remove("message_queue");
return 0;
}
Thanks in advance.
The given examples for boost::interprocess::message_queue work for me. These classes are already thread-safe, so intra-process threads are not a problem.
Here's a full example of a shared message queue. Let me know if you have trouble using it.
shared_mq.hpp:
#include <boost/interprocess/ipc/message_queue.hpp>
// could easily be made a template; make sure T is a POD!
class shared_mq {
public:
shared_mq(const char* const name,
const unsigned max_queue_size) :
shared_mq{ name, max_queue_size, delete_queue(name) }
{}
shared_mq(const char* const name) :
mq_{ boost::interprocess::open_only, name }
{}
void send(int i) {
mq_.send(&i, sizeof(i), 0 /* priority */);
}
int receive() {
int result;
boost::interprocess::message_queue::size_type recvsize;
unsigned recvpriority;
mq_.receive(&result, sizeof(result), recvsize, recvpriority);
return result;
}
private:
struct did_delete_t {};
did_delete_t delete_queue(const char* const name) {
boost::interprocess::message_queue::remove(name);
return did_delete_t{};
}
shared_mq(const char* const name,
const unsigned max_queue_size,
did_delete_t) :
mq_ { boost::interprocess::create_only, name, max_queue_size, sizeof(int) }
{}
boost::interprocess::message_queue mq_;
};
client.cpp:
#include <iostream>
#include <random>
#include <thread>
#include "shared_mq.hpp"
void send_ints(shared_mq& mq, const unsigned count) {
std::random_device rd;
std::mt19937 mt{ rd() };
std::uniform_int_distribution<int> dist{0, 10000};
for (unsigned i = 0; i != count; ++i) {
mq.send(dist(mt));
}
}
int main ()
{
std::cout << "Starting client." << std::endl;
try {
std::cout << "Creating queue..." << std::endl;
constexpr unsigned kQueueSize = 100;
shared_mq mq{ "my_queue", kQueueSize };
std::cout << "Sending ints..." << std::endl;
std::thread t1{ send_ints, std::ref(mq), 25};
std::thread t2{ send_ints, std::ref(mq), 25};
t1.join();
t2.join();
mq.send(-1); // magic sentinel value
}
catch (boost::interprocess::interprocess_exception& ex) {
std::cerr << ex.what() << std::endl;
return 1;
}
std::cout << "Finished client." << std::endl;
return 0;
}
server.cpp:
#include <iostream>
#include "shared_mq.hpp"
int main ()
{
std::cout << "Starting server." << std::endl;
try {
std::cout << "Opening queue..." << std::endl;
shared_mq mq{ "my_queue" };
std::cout << "Receiving ints..." << std::endl;
for (;;) {
const int x = mq.receive();
if (x == -1) {
// magic sentinel value
break;
}
std::cout << "Received: " << x << std::endl;
}
}
catch (boost::interprocess::interprocess_exception& ex) {
std::cerr << ex.what() << std::endl;
return 1;
}
std::cout << "Finished server." << std::endl;
return 0;
}
I'm playing with C++(11) STL and got the following problem.
The basic idea for this code is:
I have a "trigger" function, an "add" function and a flag(false by default). If the flag is false the "add" function's going to push the threadID to a queue, otherwise it's going to insert the threadID to the set. When the trigger function is called, it set the flag to "true" and move threadIDs from the queue to the set.
I initialized 100 threads and use one of the thread to run the trigger function(in the code it's thread NO.30). Ideally the result should have 0 elements in the queue and 99 elements in the set.
However, sometimes the result is correct, sometimes I missed some numbers in the set, and sometimes I got the EXC_BAD_ACCESS error.
Could anyone help? Thank you.
#include <iostream>
#include <thread>
#include <vector>
#include <unordered_set>
#include <queue>
#include <mutex>
#include <atomic>
using namespace std;
bool flag = false;
queue<int> q;
unordered_set<int> s;
mutex mu;
void trigger()
{
mu.lock();
flag = true;
mu.unlock();
while( !q.empty() ){
s.insert(q.front());
q.pop();
}
}
void add(int id)
{
mu.lock();
if( !flag )
q.push(id);
else {
if ( s.find(id) == s.end() ){
s.insert(id);
}
}
mu.unlock();
}
void missing()
{
cout << "Missing Numbers: ";
for (int i = 1; i <= 100; i++) {
if( s.find(i) == s.end() )
cout << i << " ";
}
cout << endl;
}
int main()
{
vector<thread> threads;
for (int i = 0; i < 100; i++){
if ( i == 29 ) threads.push_back(thread(trigger));
else threads.push_back(thread(add, i+1));
}
for (int i = 0; i < 100; i++){
threads[i].join();
}
cout << "Q size: " << q.size() << endl;
cout << "S size: " << s.size() << endl;
missing();
}
You have 1 thread executing the trigger function and many threads executing the add function. Furthermore, you take care to guard some of the shared state but not all of it. See my comments/questions in the below code snippets.
void trigger()
{
// Only the 'flag' is protected from concurrent acceess
mu.lock();
flag = true;
mu.unlock();
// Why isn't 'q' or 's' protected by a lock?
while( !q.empty() ){
s.insert(q.front());
q.pop();
}
}
void add(int id)
{
// In this function both 'q' and 's' are protected from concurrent access
mu.lock();
if( !flag )
q.push(id);
else {
if ( s.find(id) == s.end() ){
s.insert(id);
}
}
mu.unlock();
}
Possible Solution
In general, you should protect any state being accessed concurrently. I'd also recommend using a lock type (e.g., lock_guard) instead of locking and unlocking the mutex directly (research RAII for why this is encouraged).
#include <iostream>
#include <mutex>
#include <queue>
#include <thread>
#include <unordered_set>
#include <vector>
using namespace std;
bool flag = false;
queue<int> q;
unordered_set<int> s;
mutex mu;
void trigger()
{
lock_guard<mutex> lock(mu);
flag = true;
while (!q.empty())
{
s.insert(q.front());
q.pop();
}
}
void add(int id)
{
lock_guard<mutex> lock(mu);
if (!flag)
{
q.push(id);
}
else
{
if (s.find(id) == s.end())
{
s.insert(id);
}
}
}
void missing()
{
cout << "Missing Numbers: ";
for (int i = 1; i <= 100; ++i)
{
if (s.find(i) == s.end())
{
cout << i << " ";
}
}
cout << endl;
}
int main()
{
vector<thread> threads;
for (int i = 0; i < 100; ++i)
{
if (i == 29)
{
threads.push_back(thread(trigger));
}
else
{
threads.push_back(thread(add, i + 1));
}
}
for (int i = 0; i < 100; ++i)
{
threads[i].join();
}
cout << "Q size: " << q.size() << endl;
cout << "S size: " << s.size() << endl;
missing();
return 0;
}
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";
}