pthread_cond_wait wake many threads example - c++

pthread_cond_wait wake many threads example
Code to wake up thread 1 & 3 on some broadcast from thread 0.
Setup: Win7 with mingw32, g++ 4.8.1 with mingw32-pthreads-w32
pthread condition variable
Solution:
http://pastebin.com/X8aQ5Fz8
#include <iostream>
#include <string>
#include <list>
#include <map>
#include <pthread.h>
#include <fstream>
#include <sstream> // for ostringstream
#define N_THREAD 7
using namespace std;
// Prototypes
int main();
int scheduler();
void *worker_thread(void *ptr);
string atomic_output(int my_int, int thread_id);
// Global variables
//pthread_t thread0, thread1, thread2, thread3, thread4, thread5, thread6, thread7;
pthread_t m_thread[N_THREAD];
int count = 1;
pthread_mutex_t count_mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t condition_var = PTHREAD_COND_INITIALIZER;
// Main
int main() {
cout << "Launching main. \n";
//Start to monitor for exceptions
register_exception_handler();
//Start scheduler
scheduler();
return 0;
}
// Scheduler
int scheduler() {
// Starting scheduler log file
ofstream scheduler_log;
scheduler_log.open ("scheduler_log.txt");
//scheduler_log << "[Scheduler] Starting." << endl;
cout << "[Scheduler] Starting. \n";
// Scheduler::Main Section
int thread_id[N_THREAD];
for(int i=0;i<N_THREAD;i++) {
thread_id[i] = i;
pthread_create( &m_thread[i], NULL, worker_thread, (void *) &thread_id[i]);
}
for(int i=0;i<N_THREAD;i++)
pthread_join(m_thread[i], NULL);
cout << "[Scheduler] Ending. \n";
// Closing scheduler log file
scheduler_log.close();
return 0;
}
string atomic_output(int my_int, int thread_id) {
ostringstream stm;
stm << "Thread ";
stm << thread_id;
stm << ": ";
//count fn
stm << my_int;
stm << "\n";
//stm << "Finished. \n";
return stm.str();
}
void *worker_thread(void *ptr) {
string line;
//int boo = 0;
int thread_id = *(int *) ptr;
//if(thread_id == 0)
// pthread_mutex_lock( &count_mutex );
for(int i=0;i<10;i++) {
//boo++;
if (thread_id == 1) {
pthread_mutex_lock(&count_mutex);
while (count == 1) {
cout << "[Thread 1] Before pthread_cond_wait...\n";
pthread_cond_wait( &condition_var, &count_mutex );
cout << "[Thread 1] After pthread_cond_wait...\n";
}
pthread_mutex_unlock(&count_mutex);
}
if (thread_id == 3) {
pthread_mutex_lock(&count_mutex);
while (count == 1) {
cout << "[Thread 3] Before pthread_cond_wait...\n";
pthread_cond_wait( &condition_var, &count_mutex );
cout << "[Thread 3] After pthread_cond_wait...\n";
}
pthread_mutex_unlock(&count_mutex);
}
//count fn
line = atomic_output(i, *(int *)ptr);
cout << line;
if (i == 5) {
if(thread_id == 0) {
pthread_mutex_lock( &count_mutex );
count = 0;
pthread_mutex_unlock( &count_mutex );
pthread_cond_broadcast(&condition_var);
}
}
}
//line = atomic_output(0, *(int *)ptr);
//cout << line;
}
(old) -= What I've tried =-
*Edit: early problem in the code with while(0) instead of while(predicate). Keeping it there for easy reference with the comments.
Code 1: http://pastebin.com/rCbYjPKi
I tried to while(0) pthread_cond_wait( &condition_var, &count_mutex );
with pthread_cond_broadcast(&condition_var); ... The thread does not respect the condition.
Proof of condition non-respect : http://pastebin.com/GW1cg4fY
Thread 0: 0
Thread 0: 1
Thread 0: 2
Thread 0: 3
Thread 2: 0
Thread 6: 0
Thread 1: 0 <-- Here, Thread 1 is not supposed to tick before Thread 0 hit 5. Thread 0 is at 3.
Code 2: http://pastebin.com/g3E0Mw9W
I tried pthread_cond_wait( &condition_var, &count_mutex ); in thread 1 and 3 and the program does not return.
either thread 1, or thread 3 waits forever. Even using broadcast which says it should wake up all waiting threads. Obviously something is not working, code or lib?
More:
I've tried to unlock the mutex first, then broadcast. I've tried to broadcast then unlock. Both don't work.
I've tried to use signal instead of broadcast, same problem.
References that I can't make work (top google search)
http://www.yolinux.com/TUTORIALS/LinuxTutorialPosixThreads.html
http://docs.oracle.com/cd/E19455-01/806-5257/6je9h032r/index.html
http://www-01.ibm.com/support/knowledgecenter/ssw_i5_54/apis/users_76.htm
Code 3: http://pastebin.com/tKP7F8a8
Trying to use a predicate variable count, to fix race problem condition. Still a problem, doesn't prevent thread1 and thread3 from running when thread0 is between 0 and 5.
What would be the code to wake up thread 1 & 3 on some function call from thread0

if(thread_id == 0)
pthread_mutex_lock( &count_mutex );
for(int i=0;i<10;i++) {
//boo++;
if (thread_id == 1) {
while(0)
pthread_cond_wait( &condition_var, &count_mutex );
}
None of this makes any sense. The correct way to wait for a condition variable is:
pthread_mutex_lock(&mutex_associated_with_condition_variable);
while (!predicate)
pthread_cond_wait(&condition_variable, mutex_associated_with_condition_variable);
Notice:
The mutex must be locked.
The predicate (thing you are waiting for) must be checked before waiting.
The wait must be in a loop.
Breaking any of these three rules will cause the kind of problems you are seeing. Your main problem is that you break the second rule, waiting even when the thing you want to wait for has already happened.

Related

Multi-thread. Undefined behaviour with two while loops in two different thread

#include <mutex>
using namespace std;
int counter = 0;
mutex m;
void thread1() {
while(1) {
m.lock();
cout << "th1 " << counter << endl;
++counter;
if (counter == 300) {
m.unlock();
break;
}
m.unlock();
}
}
void thread2() {
while(1) {
m.lock();
cout << "th2 " << counter << endl;
if (counter == 10) {
counter = 300;
m.unlock();
break;
}
m.unlock();
}
}
int main(int argc, const char * argv[]) {
thread th1(thread1);
thread th2(thread2);
th1.join();
th2.join();
return 0;
}
I'm running two threads with while loops. Why despite the fact that I use mutex lock and unlock result of this code is different every time.
First code from function thread1 is executed X-times, then code from function thread2 is executed y-times.
Shouldn't them be executed one after another .. thread1 -> thread2 -> thread1 -> etc ?
This is non-deterministic because you have a race condition.
Every time you unlock the mutex both threads race to lock it again.
Also in your code you can increment over 10 and miss the exit condition in thread2 which is not what I think you want.
One way you could sync the execution to be what you described (thread1, thread2, thread1, etc..) is by using a condition variable (std::condition_variable).
Here is your code with some slight modification to get the sync behavior:
#include <mutex>
#include <iostream>
using namespace std;
int counter = 0;
bool flag = false;
mutex m;
condition_variable c;
void thread1() {
while(1) {
unique_lock<mutex> lk(m);
c.wait(lk, []{ return flag; });
cout << "th1 " << counter << endl;
if (counter == 300) {
flag=!flag;
lk.unlock();
c.notify_one();
break;
}
counter++;
flag=!flag;
lk.unlock();
c.notify_one();
}
}
void thread2() {
while(1) {
unique_lock<mutex> lk(m);
c.wait(lk, []{ return !flag; });
cout << "th2 " << counter << endl;
if (counter == 10) {
counter = 300;
flag=!flag;
lk.unlock();
c.notify_one();
break;
}
flag=!flag;
lk.unlock();
c.notify_one();
}
}
int main(int argc, const char * argv[]) {
thread th1(thread1);
thread th2(thread2);
th1.join();
th2.join();
return 0;
}
And the output:
th2 0
th1 0
th2 1
th1 1
th2 2
th1 2
th2 3
th1 3
th2 4
th1 4
th2 5
th1 5
th2 6
th1 6
th2 7
th1 7
th2 8
th1 8
th2 9
th1 9
th2 10
th1 300
then the program exits...
A couple of notes:
The threads are sync'd on the bool flag variable.
flag is used to create the predicate used in the wait methods called on the conditional_variable
c.wait(lk, []{ return flag; });
which is just a lambda which returns the flag current value.
th1 triggers on flag==true and th2 on flag==false.
The notify_one method tells the waiting thread to check its condition.
And we use a unique_lock instance specifically because we need to be able to manually lock/unlock the lock based on the condition.

Cpp program using producer and consumer (mutex locks) on a shared buffer

I have a c++ code where I am trying to produce some values into thread and consume it using 2 other consumer threads. Mutex locks are used to provide synhronisation. But output does not show a random progress for the threads, as in, producer produces 5 at a time, 1 of the consumer consumes it all at a time not giving the other consumer or the producer a chance before it completely consumes the queue. ANy help would be much appreciated. I am also attaching the code and sample output.
// CPP program to demonstrate the given task
`#include <iostream>`
`#include <pthread.h>`
#include <queue>
#include <stdlib.h>
#include<unistd.h>
#define MAX 10
using namespace std;
// Declaring global variables
int sum_B = 0, sum_C = 0;
int consumerCount1 = 0;
int consumerCount2 = 0;
// Shared queue
queue<int> Q;
int item=0;
// Function declaration of all required functions
void* producerFun(void*);
void* add_B(void*);
void* add_C(void*);
// Getting the mutex
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t dataNotProduced =
PTHREAD_COND_INITIALIZER;
pthread_cond_t dataNotConsumed =
PTHREAD_COND_INITIALIZER;
// Function to generate random numbers and
// push them into queue using thread A
void* producerFun(void*)
{
static int producerCount = 0;
// Initialising the seed
srand(time(NULL));
while (1) {
// Getting the lock on queue using mutex
pthread_mutex_lock(&mutex);
if (Q.size() < MAX && item < MAX)
{
// Getting the random number
int num = rand() % 10 + 1;
// Pushing the number into queue
Q.push(num);
producerCount++;
item++;
cout << "Produced: " << num << " item: "<<item<<endl;
pthread_cond_broadcast(&dataNotProduced);
}
// If queue is full, release the lock and return
else if (item == MAX) {
pthread_mutex_unlock(&mutex);
cout<<"\nLeaving";
//sleep(1);
continue;
}
// If some other thread is exectuing, wait
/*else {
cout << ">> Producer is in wait.." << endl;
pthread_cond_wait(&dataNotConsumed, &mutex);
}*/
// Get the mutex unlocked
pthread_mutex_unlock(&mutex);
//sleep(0.5);
}
}
// Function definition for consumer thread B
void* add_B(void*)
{
while (1) {
// Getting the lock on queue using mutex
pthread_mutex_lock(&mutex);
// Pop only when queue has at least 1 element
if (Q.size() > 0) {
// Get the data from the front of queue
int data = Q.front();
// Add the data to the integer variable
// associated with thread B
sum_B += data;
consumerCount1++;
// Pop the consumed data from queue
Q.pop();
item--;
cout << "B thread consumed: " << data << "cc1: "<<consumerCount1<<endl;
//pthread_cond_signal(&dataNotConsumed);
}
// Check if consmed numbers from both threads
// has reached to MAX value
/*else if (consumerCount2 + consumerCount1 == MAX) {
pthread_mutex_unlock(&mutex);
return NULL;
}*/
// If some other thread is exectuing, wait
else {
cout << "B is in wait.." << endl;
pthread_cond_wait(&dataNotProduced, &mutex);
}
// Get the mutex unlocked
pthread_mutex_unlock(&mutex);
//sleep(0.5);
}
}
// Function definition for consumer thread C
void* add_C(void*)
{
while (1) {
// Getting the lock on queue using mutex
pthread_mutex_lock(&mutex);
// Pop only when queue has at least 1 element
if (Q.size() > 0) {
// Get the data from the front of queue
int data = Q.front();
// Add the data to the integer variable
// associated with thread B
sum_C += data;
// Pop the consumed data from queue
Q.pop();
item--;
consumerCount2++;
cout << "C thread consumed: " << data << "cc2: "<<consumerCount2<<endl;
//pthread_cond_signal(&dataNotConsumed);
}
// Check if consmed numbers from both threads
// has reached to MAX value
/*else if (consumerCount2 + consumerCount1 == MAX)
{
pthread_mutex_unlock(&mutex);
return NULL;
}*/
// If some other thread is exectuing, wait
else {
cout << ">> C is in wait.." << endl;
// Wait on a condition
pthread_cond_wait(&dataNotProduced, &mutex);
}
// Get the mutex unlocked
pthread_mutex_unlock(&mutex);
//sleep(0.5);
}
}
// Driver code
int main()
{
// Declaring integers used to
// identify the thread in the system
pthread_t producerThread, consumerThread1, consumerThread2;
// Function to create a threads
// (pthread_create() takes 4 arguments)
int retProducer = pthread_create(&producerThread,
NULL, producerFun, NULL);
int retConsumer1 = pthread_create(&consumerThread1,
NULL, *add_B, NULL);
int retConsumer2 = pthread_create(&consumerThread2,
NULL, *add_C, NULL);
// pthread_join suspends execution of the calling
// thread until the target thread terminates
//if (!retProducer)
pthread_join(producerThread, NULL);
//if (!retConsumer1)
pthread_join(consumerThread1, NULL);
//if (!retConsumer2)
pthread_join(consumerThread2, NULL);
// Checking for the final value of thread
if (sum_C > sum_B)
cout << "Winner is Thread C" << endl;
else if (sum_C < sum_B)
cout << "Winner is Thread B" << endl;
else
cout << "Both has same score" << endl;
return 0;
}
enter image description here

Thread interruption from another thread

I'm creating 9 threads using something like this (all threads will process infinity loop)
void printStr();
thread func_thread(printStr);
void printStr() {
while (true) {
cout << "1\n";
this_thread::sleep_for(chrono::seconds(1));
}
}
I also create 10th thread to control them. How would I stop or kill any of this 9 threads from my 10th? Or suggest another mechanism please.
You can use, for example, atomic boolean:
#include <thread>
#include <iostream>
#include <vector>
#include <atomic>
using namespace std;
std::atomic<bool> run(true);
void foo()
{
while(run.load(memory_order_relaxed))
{
cout << "foo" << endl;
this_thread::sleep_for(chrono::seconds(1));
}
}
int main()
{
vector<thread> v;
for(int i = 0; i < 9; ++i)
v.push_back(std::thread(foo));
run.store(false, memory_order_relaxed);
for(auto& th : v)
th.join();
return 0;
}
EDIT (in response of your comment): you can also use a mutual variable, protected by a mutex.
#include <thread>
#include <iostream>
#include <vector>
#include <mutex>
using namespace std;
void foo(mutex& m, bool& b)
{
while(1)
{
cout << "foo" << endl;
this_thread::sleep_for(chrono::seconds(1));
lock_guard<mutex> l(m);
if(!b)
break;
}
}
void bar(mutex& m, bool& b)
{
lock_guard<mutex> l(m);
b = false;
}
int main()
{
vector<thread> v;
bool b = true;
mutex m;
for(int i = 0; i < 9; ++i)
v.push_back(thread(foo, ref(m), ref(b)));
v.push_back(thread(bar, ref(m), ref(b)));
for(auto& th : v)
th.join();
return 0;
}
It is never appropriate to kill a thread directly, you should instead send a signal to the thread to tell it to stop by itself. This will allow it to clean up and finish properly.
The mechanism you use is up to you and depends on the situation. It can be an event or a state checked periodically from within the thread.
std::thread objects are non - interruptible. You will have to use another thread library like boost or pthreads to accomplish your task. Please do note that killing threads is dangerous operation.
To illustrate how to approach this problem in pthread using cond_wait and cond_signal,In the main section you could create another thread called monitor thread that will keep waiting on a signal from one of the 9 thread.
pthread_mutex_t monMutex;////mutex
pthread_cond_t condMon;////condition variable
Creating threads:
pthread_t *threads = (pthread_t*) malloc (9* sizeof(pthread_t));
for (int t=0; t < 9;t++)
{
argPtr[t].threadId=t;
KillAll=false;
rc = pthread_create(&threads[t], NULL, &(launchInThread), (void *)&argPtr[t]);
if (rc){
printf("ERROR; return code from pthread_create() is %d\n", rc);
exit(-1);
}
}
creating monitor thread:
monitorThreadarg.threadArray=threads;//pass reference of thread array to monitor thread
monitorThreadarg.count=9;
pthread_t monitor_thread;
rc= pthread_create(&monitor_thread,NULL,&monitorHadle,(void * )(&monitorThreadArg));
if (rc){
printf("ERROR; return code from pthread_create() is %d\n", rc);
exit(-1);
}
then wait on 9 threads and monitor thread:
for (s=0; s < 9;s++)
{
pthread_join(threads[s], &status);
}
pthread_cond_signal(&condMon);// if all threads finished successfully then signal monitor thread too
pthread_join(monitor_thread, &status);
cout << "joined with monitor thread"<<endl;
The monitor function would be something like this:
void* monitorHadle(void* threadArray)
{
pthread_t* temp =static_cast<monitorThreadArg*> (threadArray)->threadArray;
int number =static_cast<monitorThreadArg*> (threadArray)->count;
pthread_mutex_lock(&monMutex);
mFlag=1;//check so that monitor threads has initialised
pthread_cond_wait(&condMon,&monMutex);// wait for signal
pthread_mutex_unlock(&monMutex);
void * status;
if (KillAll==true)
{
printf("kill all \n");
for (int i=0;i<number;i++)
{
pthread_cancel(temp[i]);
}
}
}
the function what will be launched over 9 threads should be something like this:
void launchInThread( void *data)
{
pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL);
while(1)
{
try
{
throw("exception whenever your criteria is met");
}
catch (string x)
{
cout << "exception form !! "<< pthread_self() <<endl;
KillAll=true;
while(!mFlag);//wait till monitor thread has initialised
pthread_mutex_lock(&monMutex);
pthread_cond_signal(&condMon);//signail monitor thread
pthread_mutex_unlock(&monMutex);
pthread_exit((void*) 0);
}
}
}
Please note that if you dont't put :
thread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL);
after launching your thread then your threads wouldn't terminate on thread_cancel call.
It is necessary that you clean up up all the data before you cancel a thread.

How to check if a std::thread is still running?

How can I check if a std::thread is still running (in a platform independent way)?
It lacks a timed_join() method and joinable() is not meant for that.
I thought of locking a mutex with a std::lock_guard in the thread and using the try_lock() method of the mutex to determine if it is still locked (the thread is running), but it seems unnecessarily complex to me.
Do you know a more elegant method?
Update: To be clear: I want to check if the thread cleanly exited or not. A 'hanging' thread is considered running for this purpose.
If you are willing to make use of C++11 std::async and std::future for running your tasks, then you can utilize the wait_for function of std::future to check if the thread is still running in a neat way like this:
#include <future>
#include <thread>
#include <chrono>
#include <iostream>
int main() {
using namespace std::chrono_literals;
/* Run some task on new thread. The launch policy std::launch::async
makes sure that the task is run asynchronously on a new thread. */
auto future = std::async(std::launch::async, [] {
std::this_thread::sleep_for(3s);
return 8;
});
// Use wait_for() with zero milliseconds to check thread status.
auto status = future.wait_for(0ms);
// Print status.
if (status == std::future_status::ready) {
std::cout << "Thread finished" << std::endl;
} else {
std::cout << "Thread still running" << std::endl;
}
auto result = future.get(); // Get result.
}
If you must use std::thread then you can use std::promise to get a future object:
#include <future>
#include <thread>
#include <chrono>
#include <iostream>
int main() {
using namespace std::chrono_literals;
// Create a promise and get its future.
std::promise<bool> p;
auto future = p.get_future();
// Run some task on a new thread.
std::thread t([&p] {
std::this_thread::sleep_for(3s);
p.set_value(true); // Is done atomically.
});
// Get thread status using wait_for as before.
auto status = future.wait_for(0ms);
// Print status.
if (status == std::future_status::ready) {
std::cout << "Thread finished" << std::endl;
} else {
std::cout << "Thread still running" << std::endl;
}
t.join(); // Join thread.
}
Both of these examples will output:
Thread still running
This is of course because the thread status is checked before the task is finished.
But then again, it might be simpler to just do it like others have already mentioned:
#include <thread>
#include <atomic>
#include <chrono>
#include <iostream>
int main() {
using namespace std::chrono_literals;
std::atomic<bool> done(false); // Use an atomic flag.
/* Run some task on a new thread.
Make sure to set the done flag to true when finished. */
std::thread t([&done] {
std::this_thread::sleep_for(3s);
done = true;
});
// Print status.
if (done) {
std::cout << "Thread finished" << std::endl;
} else {
std::cout << "Thread still running" << std::endl;
}
t.join(); // Join thread.
}
Edit:
There's also the std::packaged_task for use with std::thread for a cleaner solution than using std::promise:
#include <future>
#include <thread>
#include <chrono>
#include <iostream>
int main() {
using namespace std::chrono_literals;
// Create a packaged_task using some task and get its future.
std::packaged_task<void()> task([] {
std::this_thread::sleep_for(3s);
});
auto future = task.get_future();
// Run task on new thread.
std::thread t(std::move(task));
// Get thread status using wait_for as before.
auto status = future.wait_for(0ms);
// Print status.
if (status == std::future_status::ready) {
// ...
}
t.join(); // Join thread.
}
An easy solution is to have a boolean variable that the thread sets to true on regular intervals, and that is checked and set to false by the thread wanting to know the status. If the variable is false for to long then the thread is no longer considered active.
A more thread-safe way is to have a counter that is increased by the child thread, and the main thread compares the counter to a stored value and if the same after too long time then the child thread is considered not active.
Note however, there is no way in C++11 to actually kill or remove a thread that has hanged.
Edit How to check if a thread has cleanly exited or not: Basically the same technique as described in the first paragraph; Have a boolean variable initialized to false. The last thing the child thread does is set it to true. The main thread can then check that variable, and if true do a join on the child thread without much (if any) blocking.
Edit2 If the thread exits due to an exception, then have two thread "main" functions: The first one have a try-catch inside which it calls the second "real" main thread function. This first main function sets the "have_exited" variable. Something like this:
std::atomic<bool> thread_done = false;
void *thread_function(void *arg)
{
void *res = nullptr;
try
{
res = real_thread_function(arg);
}
catch (...)
{
}
thread_done = true;
return res;
}
This simple mechanism you can use for detecting finishing of a thread without blocking in join method.
std::thread thread([&thread]() {
sleep(3);
thread.detach();
});
while(thread.joinable())
sleep(1);
You can always check if the thread's id is different than std::thread::id() default constructed.
A Running thread has always a genuine associated id.
Try to avoid too much fancy stuff :)
Create a mutex that the running thread and the calling thread both have access to. When the running thread starts it locks the mutex, and when it ends it unlocks the mutex. To check if the thread is still running, the calling thread calls mutex.try_lock(). The return value of that is the status of the thread. (Just make sure to unlock the mutex if the try_lock worked)
One small problem with this, mutex.try_lock() will return false between the time the thread is created, and when it locks the mutex, but this can be avoided using a slightly more complex method.
Surely have a mutex-wrapped variable initialised to false, that the thread sets to true as the last thing it does before exiting. Is that atomic enough for your needs?
I checked both systems:
-Using thread+atomic: take 9738 milliseconds
-Using future+async: take 7746 milliseconds
Not threads: 56000milliseconds
Using a Core-I7 6 cores laptop
My code creates 4000 threads, but no more than 12 running every time.
Here is the code:
#include <iostream>
#include <thread>
#include <future>
#include <chrono>
#include <mutex> // std::mutex
#include <atomic>
#include <chrono>
#pragma warning(disable:4996)
#pragma warning(disable:6031)
#pragma warning(disable:6387)//strout
#pragma warning(disable:26451)
using namespace std;
const bool FLAG_IMPRIME = false;
const int MAX_THREADS = 12;
mutex mtx; // mutex for critical section
atomic <bool> th_end[MAX_THREADS];
atomic <int> tareas_acabadas;
typedef std::chrono::high_resolution_clock t_clock; //SOLO EN WINDOWS
std::chrono::time_point<t_clock> start_time, stop_time; char null_char;
void timer(const char* title = 0, int data_size = 1) { stop_time = t_clock::now(); double us = (double)chrono::duration_cast<chrono::microseconds>(stop_time - start_time).count(); if (title) printf("%s time = %7lgms = %7lg MOPs\n", title, (double)us * 1e-3, (double)data_size / us); start_time = t_clock::now(); }
class c_trim
{
char line[200];
thread th[MAX_THREADS];
double th_result[MAX_THREADS];
int th_index;
double milliseconds_commanded;
void hilo(int hindex,int milliseconds, double& milliseconds2)
{
sprintf(line, "%i:%ia ",hindex, milliseconds); imprime(line);
this_thread::sleep_for(std::chrono::milliseconds(milliseconds));
milliseconds2 = milliseconds * 1000;
sprintf(line, "%i:%ib ", hindex, milliseconds); imprime(line);
tareas_acabadas++; th_end[hindex] = true;
}
int wait_first();
void imprime(char* str) { if (FLAG_IMPRIME) { mtx.lock(); cout << str; mtx.unlock(); } }
public:
void lanzatareas();
vector <future<void>> futures;
int wait_first_future();
void lanzatareas_future();//usa future
};
int main()
{
c_trim trim;
timer();
trim.lanzatareas();
cout << endl;
timer("4000 tareas using THREAD+ATOMIC:", 4000);
trim.lanzatareas_future();
cout << endl;
timer("4000 tareas using FUTURE:", 4000);
cout << endl << "Tareas acabadas:" << tareas_acabadas << endl;
cout << "=== END ===\n"; (void)getchar();
}
void c_trim::lanzatareas()
{
th_index = 0;
tareas_acabadas = 0;
milliseconds_commanded = 0;
double *timeout=new double[MAX_THREADS];
int i;
for (i = 0; i < MAX_THREADS; i++)
{
th_end[i] = true;
th_result[i] = timeout[i] = -1;
}
for (i = 0; i < 4000; i++)
{
int milliseconds = 5 + (i % 10) * 2;
{
int j = wait_first();
if (th[j].joinable())
{
th[j].join();
th_result[j] = timeout[j];
}
milliseconds_commanded += milliseconds;
th_end[j] = false;
th[j] = thread(&c_trim::hilo, this, j, milliseconds, std::ref(timeout[j]));
}
}
for (int j = 0; j < MAX_THREADS; j++)
if (th[j].joinable())
{
th[j].join();
th_result[j] = timeout[j];
}
delete[] timeout;
cout <<endl<< "Milliseconds commanded to wait=" << milliseconds_commanded << endl;
}
void c_trim::lanzatareas_future()
{
futures.clear();
futures.resize(MAX_THREADS);
tareas_acabadas = 0;
milliseconds_commanded = 0;
double* timeout = new double[MAX_THREADS];
int i;
for (i = 0; i < MAX_THREADS; i++)
{
th_result[i] = timeout[i] = -1;
}
for (i = 0; i < 4000; i++)
{
int milliseconds = 5 + (i % 10) * 2;
{
int j;
if (i < MAX_THREADS) j = i;
else
{
j = wait_first_future();
futures[j].get();
th_result[j] = timeout[j];
}
milliseconds_commanded += milliseconds;
futures[j] = std::async(std::launch::async, &c_trim::hilo, this, j, milliseconds, std::ref(timeout[j]));
}
}
//Last MAX_THREADS:
for (int j = 0; j < MAX_THREADS; j++)
{
futures[j].get();
th_result[j] = timeout[j];
}
delete[] timeout;
cout << endl << "Milliseconds commanded to wait=" << milliseconds_commanded << endl;
}
int c_trim::wait_first()
{
int i;
while (1)
for (i = 0; i < MAX_THREADS; i++)
{
if (th_end[i] == true)
{
return i;
}
}
}
//Espera que acabe algun future y da su index
int c_trim::wait_first_future()
{
int i;
std::future_status status;
while (1)
for (i = 0; i < MAX_THREADS; i++)
{
status = futures[i].wait_for(0ms);
if (status == std::future_status::ready)
return i;
}
}
I also had this problem very recently. Tried with the C++20 std::jthread using the shared-stop state to check if the thread is over, but inside the thread the std::stop_token argument is a readonly and doesn't indicate to outside when the thread finishes.
So I created a simple class (nes::uthread) extending std::thread with a flag to indicate it's finished. Example:
#include <atomic>
#include <chrono>
#include <iostream>
#include <memory>
#include <thread>
namespace nes {
class uthread final
{
std::unique_ptr<std::atomic<bool>> m_finished;
std::thread m_thr;
public:
uthread()
: m_finished { std::make_unique<std::atomic<bool>>(true) }
{}
template <class Function, class... Args>
uthread(Function&& f, Args&&... args)
: m_finished { std::make_unique<std::atomic<bool>>(false) }
, m_thr {
[](std::atomic<bool>& finished, Function&& ff, Args&&... aargs) {
try {
std::forward<Function>(ff)(std::forward<Args>(aargs)...);
finished = true;
} catch (...) {
finished = true;
throw;
}
},
std::ref(*m_finished), std::forward<Function>(f),
std::forward<Args>(args)...
}
{}
uthread(const uthread&) = delete;
uthread(uthread&&) = default;
uthread& operator=(const uthread&) = delete;
uthread& operator=(uthread&&) = default;
[[nodiscard]] std::thread::id get_id() const noexcept {
return m_thr.get_id(); }
[[nodiscard]] bool joinable() const noexcept { return m_thr.joinable(); }
void join() { m_thr.join(); }
[[nodiscard]] const std::atomic<bool>& finished() const noexcept {
return *m_finished; }
};
}
int main()
{
using namespace std;
using namespace std::chrono;
using namespace std::chrono_literals;
using namespace nes;
{
cout << "std::thread join() termination\n";
atomic<bool> finished = false;
thread t { [&finished] {
this_thread::sleep_for(2s);
finished = true;
cout << "thread ended\n";
}};
for (int i = 0; i < 5; i++) {
cout << t.get_id() << ".join() " << t.joinable()
<< " finished: " << finished << '\n';
this_thread::sleep_for(1s);
}
t.join();
}
cout << '\n';
{
cout << "std::jthread join() termination\n";
jthread t {[](stop_token st) {
this_thread::sleep_for(2s);
cout << "thread ended. stop possible: " << st.stop_possible() << '\n';
}};
auto st = t.get_stop_source();
for (int i = 0; i < 5; i++) {
cout << t.get_id() << ".join() " << t.joinable()
<< " finished: " << !st.stop_possible() << '\n';
this_thread::sleep_for(1s);
}
}
cout << '\n';
{
cout << "nes::uthread join() termination\n";
uthread t {[] {
this_thread::sleep_for(2s);
cout << "thread ended\n";
}};
for (int i = 0; i < 5; i++) {
cout << t.get_id() << ".join() " << t.joinable()
<< " finished: " << t.finished() << '\n';
this_thread::sleep_for(1s);
}
t.join();
}
}
Possible prints:
std::thread join() termination
2.join() 1 finished: 0
2.join() 1 finished: 0
thread ended
2.join() 1 finished: 1
2.join() 1 finished: 1
2.join() 1 finished: 1
std::jthread join() termination
3.join() 1 finished: 0
3.join() 1 finished: 0
thread ended. stop possible: 1
3.join() 1 finished: 0
3.join() 1 finished: 0
3.join() 1 finished: 0
nes::uthread join() termination
4.join() 1 finished: 0
4.join() 1 finished: 0
thread ended
4.join() 1 finished: 1
4.join() 1 finished: 1
4.join() 1 finished: 1
You can use std::jthread in nes::uthread so you don't need to join.

Some boost thread questions C++

I am using boost::thread, and I meet some problems.
The thing is, are there any ways I can join a thread before the last join finish?
for example,
int id=1;
void temp()
{
int theardID = id++;
for(int i=0;i<3;i++)
{
cout<<theardID << " : "<<i<<endl;
boost::this_thread::sleep(boost::posix_time::millisec(100));
}
}
int main(void)
{
boost::thread thrd1(temp);
thrd1.join();
boost::thread thrd2(temp);
boost::thread thrd3(temp);
thrd2.join();
thrd3.join();
return 0;
}
In this simple example, the order of output may be:
1:0
1:1
1:2
2:0
3:0
3:1
2:1
2:2
3:2
As the above example, we can see find out that thrd2 and thrd3 start to run after thrd1 finish.
Are there any ways to let thrd2 and thrd3 run before thrd1 finish?
You can use Boost.Thread's condition variables to synchronize on a condition more complex than what join can provide. Here's a example based on yours:
#include <iostream>
#include <boost/thread.hpp>
#include <boost/thread/locks.hpp>
#include <boost/thread/mutex.hpp>
#include <boost/thread/condition_variable.hpp>
boost::mutex mutex;
boost::condition_variable cond;
// These three variables protected by mutex
bool finishedFlag = false;
int finishedID = 0;
int finishedCount = 0;
int id=1;
void temp()
{
int threadID = id++;
for(int i=0;i<3;i++)
{
std::cout << threadID << " : " << i << std::endl;
boost::this_thread::sleep(boost::posix_time::millisec(100));
}
{
boost::lock_guard<boost::mutex> lock(mutex);
finishedFlag = true;
finishedID = threadID;
++finishedCount;
}
cond.notify_one();
}
int main(void)
{
boost::thread thrd1(temp);
boost::this_thread::sleep(boost::posix_time::millisec(300));
boost::thread thrd2(temp);
boost::thread thrd3(temp);
boost::unique_lock<boost::mutex> lock(mutex);
while (finishedCount < 3)
{
while (finishedFlag != true)
{
// mutex is released while we wait for cond to be signalled.
cond.wait(lock);
// mutex is reacquired as soon as we finish waiting.
}
finishedFlag = false;
if (finishedID == 1)
{
// Do something special about thrd1 finishing
std::cout << "thrd1 finished" << std::endl;
}
};
// All 3 threads finished at this point.
return 0;
}
The join function means "stop this thread until that thread finishes." It's a simple tool for a simple purpose: ensuring that, past this point in the code, thread X is finished.
What you want to do isn't a join operation at all. What you want is some kind of synchronization primitive to communicate and synchronize behavior between threads. Boost.Thread has a number of alternatives for synchronization, from conditions to mutexes.