I am working on a project in which I am using threads. The threads are launched with std::async and I ran into some things with member variables in a class that I do not understand. In the code below there are four different implementations of the thread launching function "start_thread_n". The four different functions give somewhat different results when executed and the output I get when running them is shown in the comment before each of the functions. The difference between the functions is in the call std::async(std::launch::async, &ThreadTest::run, &h) and specifically the param "h". What I would like to get is what start_thread_3 delivers (and _4). The difference in behaviour is what the variable m_a contains at different places in the execution of the code, as can be seen in the print outs to the screen (in the comments before each function).
Can you hint on why I get the different results? I run on Linux with C++14.
Many thanks
#include <future>
#include <thread>
#include <vector>
#include <signal.h>
sig_atomic_t g_stop(false);
std::vector<std::future<void>> my_futures;
std::future<void> g_thread;
class ThreadTest
{
public:
ThreadTest();
void run();
private:
unsigned m_a;
};
ThreadTest::ThreadTest()
{
m_a = 1;
std::cout << m_a << std::endl;
}
void ThreadTest::run()
{
std::cout << "Thread started" << std::endl;
while (not g_stop) {
std::cout << "." << std::flush;
std::this_thread::sleep_for(std::chrono::milliseconds(100));
}
std::cout << std::endl;
std::cout << m_a << std::endl;
std::cout << "Thread stopped" << std::endl;
}
void start_thread_1();
void start_thread_2();
void start_thread_3();
ThreadTest start_thread_4();
void stop_threads();
int main()
{
start_thread_1();
std::this_thread::sleep_for(std::chrono::milliseconds(1000));
g_stop = true;
stop_threads();
}
/*
* > ./thread_test
* 1
* Thread started
* ..........
* 0
* Thread stopped
*/
void start_thread_1()
{
ThreadTest h;
g_thread = std::async(std::launch::async, &ThreadTest::run, &h);
my_futures.push_back(std::move(g_thread));
}
/*
* > ./thread_test
* Thread started
* ..........
* fish: “./thread_test” terminated by signal SIGSEGV (Address boundary error)
*/
void start_thread_2()
{
std::shared_ptr<ThreadTest> h;
g_thread = std::async(std::launch::async, &ThreadTest::run, h);
my_futures.push_back(std::move(g_thread));
}
/*
* > ./thread_test
* 1
* Thread started
* ..........
* 1
* Thread stopped
*/
void start_thread_3()
{
ThreadTest h;
g_thread = std::async(std::launch::async, &ThreadTest::run, h);
my_futures.push_back(std::move(g_thread));
}
/*
* > ./thread_test
* 1
* Thread started
* ..........
* 1
* Thread stopped
*/
ThreadTest start_thread_4()
{
ThreadTest h;
g_thread = std::async(std::launch::async, &ThreadTest::run, h);
my_futures.push_back(std::move(g_thread));
return h;
}
void stop_threads()
{
size_t m = my_futures.size();
for(size_t n = 0; n < m; n++) {
auto e = std::move(my_futures.back());
e.get();
my_futures.pop_back();
}
}```
Related
I used the following code to create a timer object in my c++ application running on a debian 8.
class Timer
{
private:
std::condition_variable cond_;
std::mutex mutex_;
int duration;
void *params;
public:
Timer::Timer(void (*func)(void*))
{
this->handler = func;
this->duration = 0;
this->params = NULL;
};
Timer::~Timer(){};
void Timer::start(int duree, void* handlerParams)
{
this->duration = duree;
this->params = handlerParams;
/*
* Launch the timer thread and wait it
*/
std::thread([this]{
std::unique_lock<std::mutex> mlock(mutex_);
std::cv_status ret = cond_.wait_for(mlock,
std::chrono::seconds(duration));
if ( ret == std::cv_status::timeout )
{
handler(params);
}
}).detach();
};
void Timer::stop()
{
cond_.notify_all();
}
};
It works correctly under gdb and under normal conditions, but in a load test of 30 requests or more, it crashes with the assertion :
nptl/pthread_mutex_lock.c:350: __pthread_mutex_cond_lock_full: Assertion `(-(e)) != 3 || !robust' failed.
I don't understand the cause of this assertion. Can anyone help me please ??
Thank you
Basically you have a detached thread that accesses the timer object, so it's likely that you destroyed the Timer object but the thread is still running and accessing it's member(mutex, conditional variable).
The assert itself says, from glibc source code, that the owner of the mutex has died.
Thanks a lot for your comments ! I'll try to change the thread detach, and do the load tests.
This is a MVCE of my problem, which is a part of a huge application.
/**
* \file Timer.hxx
* \brief Definition of Timer class.
*/
#include <chrono>
#include <thread>
#include <mutex>
#include <condition_variable>
class Timer
{
private:
std::condition_variable cond_;
std::mutex mutex_;
int duration;
void *params;
public:
Timer(void (*func)(void*));
~Timer();
void (*handler)(void*);
void start(int duree, void* handlerParams);
void stop();
};
/*
* Timer.cxx
*/
#include "Timer.hxx"
Timer::Timer(void (*func)(void*))
{
//this->set_handler(func, params);
this->handler = func;
this->duration = 0;
this->params = NULL;
}
Timer::~Timer()
{
}
void Timer::start(int duree, void* handlerParams)
{
this->duration = duree;
this->params = handlerParams;
/*
* Launch the timer thread and wait it
*/
std::thread([this]{
std::unique_lock<std::mutex> mlock(mutex_);
std::cv_status ret = cond_.wait_for(mlock, std::chrono::seconds(duration));
if ( ret == std::cv_status::timeout )
{
handler(params);
}
}).detach();
}
void Timer::stop()
{
cond_.notify_all();
}
/*
* MAIN
*/
#include <stdio.h>
#include <iostream>
#include <unistd.h>
#include "Timer.hxx"
using namespace std;
void timeoutHandler(void* params)
{
char* data= (char*)params;
cout << "Timeout triggered !! Received data is: " ;
if (data!=NULL)
cout << data << endl;
}
int main(int argc, char **argv)
{
int delay=5;
char data[20] ="This is a test" ;
Timer *t= new Timer(&timeoutHandler) ;
t->start(delay, data);
cout << "Timer started !! " << endl;
sleep(1000);
t->stop();
delete t;
cout << "Timer deleted !! " << endl;
return 0;
}
Below is my code, my problem is that readEvent() function never gets called.
Header file
class MyServer
{
public :
MyServer(MFCPacketWriter *writer_);
~MyServer();
void startReading();
void stopReading();
private :
MFCPacketWriter *writer;
pthread_t serverThread;
bool stopThread;
static void *readEvent(void *);
};
CPP file
MyServer::MyServer(MFCPacketWriter *writer_):writer(writer_)
{
serverThread = NULL;
stopThread = false;
LOGD(">>>>>>>>>>>>> constructed MyServer ");
}
MyServer::~MyServer()
{
writer = NULL;
stopThread = true;
}
void MyServer::startReading()
{
LOGD(">>>>>>>>>>>>> start reading");
if(pthread_create(&serverThread,NULL,&MyServer::readEvent, this) < 0)
{
LOGI(">>>>>>>>>>>>> Error while creating thread");
}
}
void *MyServer::readEvent(void *voidptr)
{
// this log never gets called
LOGD(">>>>>>>>>>>>> readEvent");
while(!MyServer->stopThread){
//loop logic
}
}
Another class
MyServer MyServer(packet_writer);
MyServer.startReading();
Since you are not calling pthread_join, your main thread is terminating without waiting for your worker thread to finish.
Here is a simplified example that reproduces the problem:
#include <iostream>
#include <pthread.h>
class Example {
public:
Example () : thread_() {
int rcode = pthread_create(&thread_, nullptr, Example::task, nullptr);
if (rcode != 0) {
std::cout << "pthread_create failed. Return code: " << rcode << std::endl;
}
}
static void * task (void *) {
std::cout << "Running task." << std::endl;
return nullptr;
}
private:
pthread_t thread_;
};
int main () {
Example example;
}
View Results
No output is produced when running this program, even though pthread_create was successfully called with Example::task as the function parameter.
This can be fixed by calling pthread_join on the thread:
#include <iostream>
#include <pthread.h>
class Example {
public:
Example () : thread_() {
int rcode = pthread_create(&thread_, nullptr, Example::task, nullptr);
if (rcode != 0) {
std::cout << "pthread_create failed. Return code: " << rcode << std::endl;
}
}
/* New code below this point. */
~Example () {
int rcode = pthread_join(thread_, nullptr);
if (rcode != 0) {
std::cout << "pthread_join failed. Return code: " << rcode << std::endl;
}
}
/* New code above this point. */
static void * task (void *) {
std::cout << "Running task." << std::endl;
return nullptr;
}
private:
pthread_t thread_;
};
int main () {
Example example;
}
View Results
Now the program produces the expected output:
Running task.
In your case, you could add a call to pthread_join to the destructor of your MyServer class.
I am new to multithreading.
When I am running the below program it is giving output as
Function1
Function2
1000...1001
but when I am debugging the program it is giving output as expected.
1000...1001
Function1
Function2
So,I think at directly running time (without debugging) mode it is getting some synchronization problem. But one thing confuses me that, I am using mutex then why synchronization problem is happening?
Please help me.
#include <iostream>
#include <cstdlib>
#include <pthread.h>
using namespace std;
pthread_mutex_t myMutex;
void * function1(void * arg);
void * function2(void * arg);
void * function0(void * arg);
int count = 0;
const int COUNT_DONE = 10;
main()
{
pthread_t thread1, thread2, thread0;
pthread_mutex_init(&myMutex, 0);
pthread_create(&thread0, NULL, &function0, NULL );
pthread_create(&thread1, NULL, &function1, NULL );
pthread_create(&thread2, NULL, &function2, NULL );
pthread_join(thread0, NULL );
pthread_join(thread1, NULL );
pthread_join(thread2, NULL );
pthread_mutex_destroy(&myMutex);
return 0;
}
void *function1(void * arg)
{
cout << "Function1\n";
}
void *function0(void *arg)
{
int i, j;
pthread_mutex_lock(&myMutex);
for (i = 0; i <= 1000; i++)
{
for (j = 0; j <= 1000; j++)
{
}
}
cout << i << "..." << j << endl;
pthread_mutex_unlock(&myMutex);
}
void *function2(void * arg)
{
cout << "Function2\n";
}
"... getting some synchronization problem" where do you see a problem?
The threads output could come in any order, as the threads are not synchronised in any case.
The mutex is used only in one thread.
Also
Function1
1000...1001
Function2
might be an expectable and valid result.
As well as:
1000
Function1
...
Function2
1001
Modifying function1() and function2() like so:
void *function1(void * arg)
{
pthread_mutex_lock(&myMutex);
cout << "Function1\n";
pthread_mutex_unlock(&myMutex);
}
void *function2(void * arg)
{
pthread_mutex_lock(&myMutex);
cout << "Function2\n";
pthread_mutex_unlock(&myMutex);
}
would protect the program from producing the 2nd of my example outputs.
I am trying to develop a console application, where I will display the system date and time in real time (or as real as I can get). This is the easy part. The hard part is that I must also have the cursor available for the user to enter information through. I can't use NCurses in my application, nor any other library that it not included in vanilla GCC 4.4 (there goes boost! Noooo....)
This is my code so far:
The realtime class, where I am incorporating the solution given by Jeremy Friesner here pthreads in c++ inside classes
#ifndef _REALTIME_H_
#define _REALTIME_H_
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
class MyThreadClass
{
public:
MyThreadClass() {/* empty */}
virtual ~MyThreadClass() {/* empty */}
/** Returns true if the thread was successfully started, false if there was an error starting the thread */
bool startMainThread()
{
return (pthread_create(&_mainThread, NULL, mainRunnerFunc, this) == 0);
}
bool startDisplayThread()
{
return (pthread_create(&_displayThread, NULL, displayThreadFunc, this) == 0);
}
/** Will not return until the main thread has exited. */
void waitForMainThreadToExit()
{
(void) pthread_join(_mainThread, NULL);
}
void waitForDisplayThreadToExit()
{
(void) pthread_join(_displayThread, NULL);
}
protected:
/** Implement this method in your subclass with the code you want your thread to run. */
virtual void mainRunner() = 0;
virtual void displayTime() = 0;
private:
static void * mainRunnerFunc(void * This) {((MyThreadClass *)This)->mainRunner(); return NULL;}
static void * displayThreadFunc(void * This) {((MyThreadClass *)This)->displayTime(); return NULL;}
pthread_t _mainThread;
pthread_t _displayThread;
};
class DynamicTime : public MyThreadClass
{
private:
const string currentDate();
void gotoxy(int,int);
void displayTime();
void mainRunner();
pthread_mutex_t mutex1;
public:
// pthread_mutex_t mutex1;
DynamicTime();
unsigned int lifeTime;
unsigned int updateTime;
void start();
int Exit;
};
const string DynamicTime::currentDate()
{
time_t now = time(0);
struct tm tstruct;
char buf[80];
tstruct = *localtime(&now);
strftime(buf,sizeof(buf),"%I:%M:%S %p, %d-%m-%y",&tstruct);
return buf;
}
DynamicTime::DynamicTime()
{
pthread_mutex_init(&(mutex1),NULL);
lifeTime=-1; /* 100 seconds */
updateTime = 1; /* 5 seconds interval */
Exit=1;
}
void DynamicTime::gotoxy(int x,int y)
{
/* go to location */
printf("\033[%d;%df",y,x);
}
void DynamicTime::displayTime()
{
pthread_mutex_lock(&mutex1);
/* save the cursor location */
printf("\033[s");
gotoxy(75,30);
cout << "Date : " << currentDate() << endl;
/* restore the cursor location */
printf("\033[u");
pthread_mutex_unlock(&mutex1);
}
void DynamicTime::mainRunner()
{
unsigned long iterate, iterate2;
int iret1,iret2;
if(lifeTime!=-1)
{
for(iterate=0;iterate<lifeTime*100000;iterate++)
{
if(iterate%(updateTime*50)==0)
{
iret2 = startDisplayThread();
waitForDisplayThreadToExit();
}
for(iterate2=0;iterate2<100000;iterate2++);
}
std::cout << "Ending main thread..." << endl;
}
else
{
while(1&Exit) /* infinitely */
{
iret2 = startDisplayThread();
waitForDisplayThreadToExit();
for(iterate2=0;iterate2<100000;iterate2++);
}
std::cout << "Exiting Application.... " << endl;
}
}
void DynamicTime::start()
{
//system("clear");
//cout << "Starting...." << endl;
if(startMainThread()==false)
{
std::cerr << "Coudln't start main Thread! " << endl;
}
/* call this function in the main program
* else
{
waitForMainThreadToExit();
}*/
}
/* Example
* on how to use the program
* int main()
{
DynamicTime DT;
DT.lifeTime = 100;
DT.start();
return 0;
}
*/
#endif
and my example program, where I am trying to read data from the user, while showing the time at the same time:
//#include <iostream>
#include "realtime2.h"
int main()
{
DynamicTime DT;
string temp="abcd";
DT.start();
while(temp!="exit")
{
std::cout << "$> " ;
std::cin >> temp;
}
DT.waitForMainThreadToExit();
return 0;
}
This would be called a fully-functional program, if only I could get the user to enter data without interruption from the display thread. Any ideas as to how to get around this ? Or if I can't get around this, what would be the proper way to do so ?
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.