I have a C++ class that does some multi-threading. Consider the pseudo-code below:
void MyClass::Open() {
loop_flag = true;
// create consumer_thread (infinite loop)
// create producer_thread (infinite loop)
}
void MyClass::Close() {
loop_flag = false;
// join producer_thread
// join consumer_thread
}
MyClass::~MyClass() {
Close();
// do other stuff here
}
Note that consumer_thread, producer_thread, and their associated functions are all encapsulated in MyClass. The caller has no clue that their calls are multi-threaded and what's going on in the background.
Now, the class is part of a larger program. The program has some initial multi-threading to handle configuration of the system since there's a ton of stuff happening at once.
Like this (pseudo-code):
int main() {
// create config_thread1 (unrelated to MyClass)
// create thread for MyClass::Open()
// ...
// join all spawned configuration threads
}
So my question is, when I call join() for the thread linked to MyClass::Open() (i.e., the configuration thread spawned in main()), what happens? Does it join() immediately (since the MyClass::Open() function just returns after creation of producer_thread and consumer_thread) or does it wait for producer_thread and consumer_thread to finish (and therefore hangs my program).
Thanks in advance for the help. In terms of implementation details, I'm using Boost threads on a Linux box.
Edited to add this diagram:
main()
|
|
|
|--->configuration_thread (that runs MyClass::Open())
|
|
|----> producer_thread
|----> consumer_thread
If I call join() on configuration_thread(), does it wait until producer_thread() and consumer_thread() are finished or does it return immediately (and producer_thread() and consumer_thread() continue to run)?
A (non detached) thread will be joignable, even after having returned from the function it was set to run, until it has been joined.
Example:
#include <iostream>
#include <thread>
#include <chrono>
using namespace std;
void foo(){
std::cout << "helper: I'm done\n";
}
int main(){
cout << "starting helper...\n";
thread helper(foo);
this::thread::sleep_for(std::chrono::seconds(5));
cout << "helper still joignable?..." << (helper.joignable()?"yes!":"no...:(") << "\n";
helper.join();
cout << "helper joined!";
cout << "helper still joignable?..." << (helper.joignable()?"really?":"not anymore!") << "\n";
cout << "done!\n";
}
Output:
starting helper...
helper: I'm done
still joinable?...yes!
helper joined!
still joinable?...not anymore!
done!
As for how much time the join method takes, I don't think this is specified, but surely it doesn't't have to wait for all the other threads to finish, or it would mean that only one thread would be able to join all the others.
From ยง30.3.5:
void Join();
Requires: joinable() is true
Effects: Blocks until the thread represented by *this had completed.
Synchronization: The completion of the thread represented by *this synchronises with the corresponding successful join() return. [Note: Operations on *this are not synchronised. * -- end note*]
[...]
Related
I'm new to C++ and I'm trying to make the console print "after 5 seconds" after 5000 ms. Then print "insta log" immediately after the new thread's declaration.
But doing so crashes with the following error:
"Debug Error!
[PROGRAM PATH]
abort() has been called
"
This is my code:
#include <iostream>
#include <thread>
#include <Windows.h>
#include <ctime>
using namespace std;
void f() {
Sleep(5000);
cout << "after 5 seconds" << endl;
}
int main() {
cout << "starting" << endl;
// Pass f and its parameters to thread
// object constructor as
thread t(&f);
cout << "insta log" << endl;
}
I'm unsure why this is happening. I've searched around and I found a "fix" but it makes my code not behave as intended.
This is the "fix"
#include <iostream>
#include <thread>
#include <Windows.h>
#include <ctime>
using namespace std;
void f() {
Sleep(5000);
cout << "after 5 seconds" << endl;
}
int main() {
cout << "starting" << endl;
// Pass f and its parameters to thread
// object constructor as
thread t(&f);
t.join();
cout << "insta log" << endl; // doesn't print for 5 seconds
}
This removes the error message but yields the main thread for 5 seconds. Which makes my code not work as intended.
Thanks in advance, any help is appreciated!
This removes the error message.
Yes.
but yields the main thread for 5 seconds.
This is not what is happening!
The main thread is waiting for your second thread t to finish (slightly different to yielding).
The problem before was that the main thread was exiting the application (and you are not allowed to have other threads running after the main thread exits (this is because what happens to the children thread is highly depended on the threading implementation and they very wildly).
In the C++ std::thread class they try and compensate for the above behavior by making the destructor terminate() if the current thread leaves scope without the child thread of execution completing.
This means you usually have to call the join() method to wait for the child to exit.
So what you usually do is 1: create a std::thread object that does some work in the background 2: while you do some work locally. Then when you have finished, 3: you call join() and wait for the child object to also finish (if it has already finished this does nothing). Then you can exit scope (and exit the main).
Which makes my code not work as intended.
int main()
{
// STUFF.
// Create your thread.
thread t(&f);
// Print any thing you want.
// i.e. do the work you want to do in main.
cout << "insta log" << endl;
// When you have finished.
// wait for the child to finish.
t.join();
} // now the std::thread::~thread check to make sure the
// child thread of execution is no longer running.
If you had clicked 'retry' in that dialog you would have seen why your code died. Its right here
~thread() noexcept {
if (joinable()) {
_STD terminate();
}
}
in the MSVC implementation of std::thread. The code says that destroying a thread thats still joinable (ie is running) is illegal. I dont know if thats c++ defined behavior, a quick search didnt show me. Anyway when you join the thread, you will wait till its OK to destroy it
Functions are already passed around as pointers, use thread t(f) instead of thread t(&f).
Moreover, since your main() neither lasts longer than the thread or calls a t.join(), the program will end before the thread finishes it's code, so that might be another reason for a crash. In fact it is probably the reason for the crash.
If you want "insta log" to print instantly, then call t.join() at the end of main(). t.join() will wait for the thread t to end before continuing.
I've been trying to develop a better understanding of C++ threading, by which I have written the following example:
#include <functional>
#include <iostream>
#include <thread>
class Test {
public:
Test() { x = 5; }
void act() {
std::cout << "1" << std::endl;
std::thread worker(&Test::changex, this);
worker.detach();
std::cout << "2" << std::endl;
}
private:
void changex() {
std::cout << "3" << std::endl;
x = 10;
std::cout << "4" << std::endl;
}
int x;
};
int main() {
Test t;
t.act();
return 0;
}
To me, I should get the following output when compiled with g++ linked with -pthread:
1
2
3
4
as the cout calls are in that order. However, the output is inconsistent. 1 and 2 are always printed in order, but sometimes the 3 and or 4 are either omitted or printed double. i.e. 12, 123, 1234, or 12344
My working theory is that the main thread exits before the worker thread begins working or completes, thus resulting in the omission of output. I can immediately think of a solution to this problem in creating a global boolean variable to signify when the worker thread has completed that the main thread waits on for a state change before exiting. This alleviates the issue.
However, this feels to me like a highly messy approach that likely has a more clean solution, especially for an issue like this that likely comes up often in threading.
Just some general advice, that holds both for using raw pthreads in C++ and for pthreads wrapped in std::thread: The best way to get readable, comprehensible and debuggable behavior is to make thread synchronization and lifetime management explicit. I.e. avoid using pthread_kill, pthread_cancel, and in most cases, avoid detaching threads and instead do explicit join.
One design pattern I like is using an std atomic flag. When main thread wants to quit, it sets the atomic flag to true. The worker threads typically do their work in a loop, and check the atomic flag reasonably often, e.g. once per lap of the loop. When they find main has ordered them to quit, they clean up and return. The main thread then join:s with all workers.
There are some special cases that require extra care, for example when one worker is stuck in a blocking syscall and/or C library function. Usually, the platform provides ways of getting out of such blocking calls without resorting to e.g. pthread_cancel, since thread cancellation works very badly with C++. One example of how to avoid blocking is the Linux manpage for getaddrinfo_a, i.e. asynchronous network address translation.
One additional nice design pattern is when workers are sleeping in e.g. select(). You can then add an extra control pipe between main and the worker. Main signals the worker to quit by send():ing one byte over the pipe, thus waking up the worker if it sleeps in select().
Example of how this could be done:
#include <functional>
#include <iostream>
#include <thread>
class Test {
std::thread worker; // worker is now a member
public:
Test() { x = 5; } // worker deliberately left without a function to run.
~Test()
{
if (worker.joinable()) // worker can be joined (act was called successfully)
{
worker.join(); // wait for worker thread to exit.
// Note destructor cannot complete if thread cannot be exited.
// Some extra brains needed here for production code.
}
}
void act() {
std::cout << "1" << std::endl;
worker = std::thread(&Test::changex, this); // give worker some work
std::cout << "2" << std::endl;
}
// rest unchanged.
private:
void changex() {
std::cout << "3" << std::endl;
x = 10;
std::cout << "4" << std::endl;
}
int x;
};
int main() {
Test t;
t.act();
return 0;
} // test destroyed here. Destruction halts and waits for thread.
Sometime I have to use std::thread to speed up my application. I also know join() waits until a thread completes. This is easy to understand, but what's the difference between calling detach() and not calling it?
I thought that without detach(), the thread's method will work using a thread independently.
Not detaching:
void Someclass::Somefunction() {
//...
std::thread t([ ] {
printf("thread called without detach");
});
//some code here
}
Calling with detaching:
void Someclass::Somefunction() {
//...
std::thread t([ ] {
printf("thread called with detach");
});
t.detach();
//some code here
}
In the destructor of std::thread, std::terminate is called if:
the thread was not joined (with t.join())
and was not detached either (with t.detach())
Thus, you should always either join or detach a thread before the flows of execution reaches the destructor.
When a program terminates (ie, main returns) the remaining detached threads executing in the background are not waited upon; instead their execution is suspended and their thread-local objects destructed.
Crucially, this means that the stack of those threads is not unwound and thus some destructors are not executed. Depending on the actions those destructors were supposed to undertake, this might be as bad a situation as if the program had crashed or had been killed. Hopefully the OS will release the locks on files, etc... but you could have corrupted shared memory, half-written files, and the like.
So, should you use join or detach ?
Use join
Unless you need to have more flexibility AND are willing to provide a synchronization mechanism to wait for the thread completion on your own, in which case you may use detach
You should call detach if you're not going to wait for the thread to complete with join but the thread instead will just keep running until it's done and then terminate without having the spawner thread waiting for it specifically; e.g.
std::thread(func).detach(); // It's done when it's done
detach basically will release the resources needed to be able to implement join.
It is a fatal error if a thread object ends its life and neither join nor detach has been called; in this case terminate is invoked.
This answer is aimed at answering question in the title, rather than explaining the difference between join and detach. So when should std::thread::detach be used?
In properly maintained C++ code std::thread::detach should not be used at all. Programmer must ensure that all the created threads gracefully exit releasing all the acquired resources and performing other necessary cleanup actions. This implies that giving up ownership of threads by invoking detach is not an option and therefore join should be used in all scenarios.
However some applications rely on old and often not well designed and supported APIs that may contain indefinitely blocking functions. Moving invocations of these functions into a dedicated thread to avoid blocking other stuff is a common practice. There is no way to make such a thread to exit gracefully so use of join will just lead to primary thread blocking. That's a situation when using detach would be a less evil alternative to, say, allocating thread object with dynamic storage duration and then purposely leaking it.
#include <LegacyApi.hpp>
#include <thread>
auto LegacyApiThreadEntry(void)
{
auto result{NastyBlockingFunction()};
// do something...
}
int main()
{
::std::thread legacy_api_thread{&LegacyApiThreadEntry};
// do something...
legacy_api_thread.detach();
return 0;
}
When you detach thread it means that you don't have to join() it before exiting main().
Thread library will actually wait for each such thread below-main, but you should not care about it.
detach() is mainly useful when you have a task that has to be done in background, but you don't care about its execution. This is usually a case for some libraries. They may silently create a background worker thread and detach it so you won't even notice it.
According to cppreference.com:
Separates the thread of execution from the thread object, allowing
execution to continue independently. Any allocated resources will be
freed once the thread exits.
After calling detach *this no longer owns any thread.
For example:
std::thread my_thread([&](){XXXX});
my_thread.detach();
Notice the local variable: my_thread, while the lifetime of my_thread is over, the destructor of std::thread will be called, and std::terminate() will be called within the destructor.
But if you use detach(), you should not use my_thread anymore, even if the lifetime of my_thread is over, nothing will happen to the new thread.
Maybe it is good idea to iterate what was mentioned in one of the answers above: When the main function is finished and main thread is closing, all spawn threads either will be terminated or suspended. So, if you are relying on detach to have a background thread continue running after the main thread is shutdown, you are in for a surprise. To see the effect try the following. If you uncomment the last sleep call, then the output file will be created and written to fine. Otherwise not:
#include <mutex>
#include <thread>
#include <iostream>
#include <fstream>
#include <array>
#include <chrono>
using Ms = std::chrono::milliseconds;
std::once_flag oflag;
std::mutex mx;
std::mutex printMx;
int globalCount{};
std::ofstream *logfile;
void do_one_time_task() {
//printMx.lock();
//std::cout<<"I am in thread with thread id: "<< std::this_thread::get_id() << std::endl;
//printMx.unlock();
std::call_once(oflag, [&]() {
// std::cout << "Called once by thread: " << std::this_thread::get_id() << std::endl;
// std::cout<<"Initialized globalCount to 3\n";
globalCount = 3;
logfile = new std::ofstream("testlog.txt");
//logfile.open("testlog.txt");
});
std::this_thread::sleep_for(Ms(100));
// some more here
for(int i=0; i<10; ++i){
mx.lock();
++globalCount;
*logfile << "thread: "<< std::this_thread::get_id() <<", globalCount = " << globalCount << std::endl;
std::this_thread::sleep_for(Ms(50));
mx.unlock();
std::this_thread::sleep_for(Ms(2));
}
std::this_thread::sleep_for(Ms(2000));
std::call_once(oflag, [&]() {
//std::cout << "Called once by thread: " << std::this_thread::get_id() << std::endl;
//std::cout << "closing logfile:\n";
logfile->close();
});
}
int main()
{
std::array<std::thread, 5> thArray;
for (int i = 0; i < 5; ++i)
thArray[i] = std::thread(do_one_time_task);
for (int i = 0; i < 5; ++i)
thArray[i].detach();
//std::this_thread::sleep_for(Ms(5000));
std::cout << "Main: globalCount = " << globalCount << std::endl;
return 0;
}
I have a vector of Timer Objects. Each Timer Object launches an std::thread that simulates a growing period. I am using a Command pattern.
What is happening is each Timer is getting executed one after another but what I really want is for one to be executed....then once finished, the next one...once finished the next...while not interfering with the main execution of the program
class Timer
{
public:
bool _bTimerStarted;
bool _bTimerCompleted;
int _timerDuration;
virtual ~Timer() { }
virtual void execute()=0;
virtual void runTimer()=0;
inline void setDuration(int _s) { _timerDuration = _s; };
inline int getDuration() { return _timerDuration; };
inline bool isTimerComplete() { return _bTimerCompleted; };
};
class GrowingTimer : public Timer
{
public:
void execute()
{
//std::cout << "Timer execute..." << std::endl;
_bTimerStarted = false;
_bTimerCompleted = false;
//std::thread t1(&GrowingTimer::runTimer, this); //Launch a thread
//t1.detach();
runTimer();
}
void runTimer()
{
//std::cout << "Timer runTimer..." << std::endl;
_bTimerStarted = true;
auto start = std::chrono::high_resolution_clock::now();
std::this_thread::sleep_until(start + std::chrono::seconds(20));
_bTimerCompleted = true;
std::cout << "Growing Timer Finished..." << std::endl;
}
};
class Timers
{
std::vector<Timer*> _timers;
struct ExecuteTimer
{
void operator()(Timer* _timer) { _timer->execute(); }
};
public:
void add_timer(Timer& _timer) { _timers.push_back(&_timer); }
void execute()
{
//std::for_each(_timers.begin(), _timers.end(), ExecuteTimer());
for (int i=0; i < _timers.size(); i++)
{
Timer* _t = _timers.at(i);
_t->execute();
//while ( ! _t->isTimerComplete())
//{
//}
}
}
};
Executing the above like:
Timers _timer;
GrowingTimer _g, g1;
_g.setDuration(BROCCOLI::growTimeSeconds);
_g1.setDuration(BROCCOLI::growTimeSeconds);
_timer.add_timer(_g);
_timer.add_timer(_g1);
start_timers();
}
void start_timers()
{
_timer.execute();
}
In Timers::execute I am trying a few different ways to execute the first and not execute the
next until I somehow signal it is done.
UPDATE:
I am now doing this to execute everything:
Timers _timer;
GrowingTimer _g, g1;
_g.setDuration(BROCCOLI::growTimeSeconds);
_g1.setDuration(BROCCOLI::growTimeSeconds);
_timer.add_timer(_g);
_timer.add_timer(_g1);
//start_timers();
std::thread t1(&Broccoli::start_timers, this); //Launch a thread
t1.detach();
}
void start_timers()
{
_timer.execute();
}
The first time completes (I see the "completed" cout), but crashes at _t->execute(); inside the for loop with an EXEC_BAD_ACCESS. I added a cout to check the size of the vector and it is 2 so both timers are inside. I do see this in the console:
this Timers * 0xbfffd998
_timers std::__1::vector<Timer *, std::__1::allocator<Timer *> >
if I change the detach() to join() everything completes without the crash, but it blocks execution of my app until those timers finish.
Why are you using threads here? Timers::execute() calls execute on a timer, then waits for it to finish, then calls execute on the next, and so forth. Why don't you just call the timer function directly in Timers::execute() rather than spawning a thread and then waiting for it?
Threads allow you to write code that executes concurrently. What you want is serial execution, so threads are the wrong tool.
Update: In the updated code you run start_timers on a background thread, which is good. However, by detaching that thread you leave the thread running past the end of the scope. This means that the timer objects _g and _g1 and even the Timers object _timers are potentially destroyed before the thread has completed. Given the time-consuming nature of the timers thread, and the fact that you used detach rather than join in order to avoid your code blocking, this is certainly the cause of your problem.
If you run code on a thread then you need to ensure that all objects accessed by that thread have a long-enough lifetime that they are still valid when the thread accesses them. For detached threads this is especially hard to achieve, so detached threads are not recommended.
One option is to create an object containing _timers, _g and _g1 along side the thread t1, and have its destructor join with the thread. All you need to do then is to ensure that the object lives until the point that it is safe to wait for the timers to complete.
If you don't want to interfere with the execution of the program, you could do something like #Joel said but also adding a thread in the Timers class which would execute the threads in the vector.
You could include a unique_ptr to the thread in GrowingTimer instead of creating it as a local object in execute and calling detach. You can still create the thread in execute, but you would do it with a unique_ptr::reset call.
Then use join instead of isTimerComplete (add a join function to the Timer base class). The isTimerComplete polling mechanism will be extremely inefficient because it will basically use up that thread's entire time slice continually polling, whereas join will block until the other thread is complete.
An example of join:
#include <iostream>
#include <chrono>
#include <thread>
using namespace std;
void threadMain()
{
this_thread::sleep_for(chrono::seconds(5));
cout << "Done sleeping\n";
}
int main()
{
thread t(threadMain);
for (int i = 0; i < 10; ++i)
{
cout << i << "\n";
}
t.join();
cout << "Press Enter to exit\n";
cin.get();
return 0;
}
Note how the main thread keeps running while the other thread does its thing. Note that Anthony's answer is right in that it doesn't really seem like you need more than one background thread that just executes tasks sequentially rather than starting a thread and waiting for it to finish before starting a new one.
I am having an issue with terminating worker threads from the main thread. So far each method I tried either leads to a race condition or dead lock.
The worker threads are stored in a inner class inside a class called ThreadPool, ThreadPool maintains a vector of these WorkerThreads using unique_ptr.
Here is the header for my ThreadPool:
class ThreadPool
{
public:
typedef void (*pFunc)(const wpath&, const Args&, Global::mFile_t&, std::mutex&, std::mutex&); // function to point to
private:
class WorkerThread
{
private:
ThreadPool* const _thisPool; // reference enclosing class
// pointers to arguments
wpath _pPath; // member argument that will be modifyable to running thread
Args * _pArgs;
Global::mFile_t * _pMap;
// flags for thread management
bool _terminate; // terminate thread
bool _busy; // is thread busy?
bool _isRunning;
// thread management members
std::mutex _threadMtx;
std::condition_variable _threadCond;
std::thread _thisThread;
// exception ptr
std::exception_ptr _ex;
// private copy constructor
WorkerThread(const WorkerThread&): _thisPool(nullptr) {}
public:
WorkerThread(ThreadPool&, Args&, Global::mFile_t&);
~WorkerThread();
void setPath(const wpath); // sets a new task
void terminate(); // calls terminate on thread
bool busy() const; // returns whether thread is busy doing task
bool isRunning() const; // returns whether thread is still running
void join(); // thread join wrapper
std::exception_ptr exception() const;
// actual worker thread running tasks
void thisWorkerThread();
};
// thread specific information
DWORD _numProcs; // number of processors on system
unsigned _numThreads; // number of viable threads
std::vector<std::unique_ptr<WorkerThread>> _vThreads; // stores thread pointers - workaround for no move constructor in WorkerThread
pFunc _task; // the task threads will call
// synchronization members
unsigned _barrierLimit; // limit before barrier goes down
std::mutex _barrierMtx; // mutex for barrier
std::condition_variable _barrierCond; // condition for barrier
std::mutex _coutMtx;
public:
// argument mutex
std::mutex matchesMap_mtx;
std::mutex coutMatch_mtx;
ThreadPool(pFunc f);
// wake a thread and pass it a new parameter to work on
void callThread(const wpath&);
// barrier synchronization
void synchronizeStartingThreads();
// starts and synchronizes all threads in a sleep state
void startThreads(Args&, Global::mFile_t&);
// terminate threads
void terminateThreads();
private:
};
So far the real issue I am having is that when calling terminateThreads() from main thread
causes dead lock or race condition.
When I set my _terminate flag to true, there is a chance that the main will already exit scope and destruct all mutexes before the thread has had a chance to wake up and terminate. In fact I have gotten this crash quite a few times (console window displays: mutex destroyed while busy)
If I add a thread.join() after I notify_all() the thread, there is a chance the thread will terminate before the join occurs, causing an infinite dead lock, as joining to a terminated thread suspends the program indefinitely.
If I detach - same issue as above, but causes program crash
If I instead use a while(WorkerThread.isRunning()) Sleep(0);
The program may crash because the main thread may exit before the WorkerThread reaches that last closing brace.
I am not sure what else to do to stop halt the main until all worker threads have terminated safely. Also, even with try-catch in thread and main, no exceptions are being caught. (everything I have tried leads to program crash)
What can I do to halt the main thread until worker threads have finished?
Here are the implementations of the primary functions:
Terminate Individual worker thread
void ThreadPool::WorkerThread::terminate()
{
_terminate = true;
_threadCond.notify_all();
_thisThread.join();
}
The actual ThreadLoop
void ThreadPool::WorkerThread::thisWorkerThread()
{
_thisPool->synchronizeStartingThreads();
try
{
while (!_terminate)
{
{
_thisPool->_coutMtx.lock();
std::cout << std::this_thread::get_id() << " Sleeping..." << std::endl;
_thisPool->_coutMtx.unlock();
_busy = false;
std::unique_lock<std::mutex> lock(_threadMtx);
_threadCond.wait(lock);
}
_thisPool->_coutMtx.lock();
std::cout << std::this_thread::get_id() << " Awake..." << std::endl;
_thisPool->_coutMtx.unlock();
if(_terminate)
break;
_thisPool->_task(_pPath, *_pArgs, *_pMap, _thisPool->coutMatch_mtx, _thisPool->matchesMap_mtx);
_thisPool->_coutMtx.lock();
std::cout << std::this_thread::get_id() << " Finished Task..." << std::endl;
_thisPool->_coutMtx.unlock();
}
_thisPool->_coutMtx.lock();
std::cout << std::this_thread::get_id() << " Terminating" << std::endl;
_thisPool->_coutMtx.unlock();
}
catch (const std::exception&)
{
_ex = std::current_exception();
}
_isRunning = false;
}
Terminate All Worker Threads
void ThreadPool::terminateThreads()
{
for (std::vector<std::unique_ptr<WorkerThread>>::iterator it = _vThreads.begin(); it != _vThreads.end(); ++it)
{
it->get()->terminate();
//it->get()->_thisThread.detach();
// if thread threw an exception, rethrow it in main
if (it->get()->exception() != nullptr)
std::rethrow_exception(it->get()->exception());
}
}
and lastly, the function that is calling the thread pool (the scan function is running on main)
// scans a path recursively for all files of selected extension type, calls thread to parse file
unsigned int Functions::Scan(wpath path, const Args& args, ThreadPool& pool)
{
wrecursive_directory_iterator d(path), e;
unsigned int filesFound = 0;
while ( d != e )
{
if (args.verbose())
std::wcout << L"Grepping: " << d->path().string() << std::endl;
for (Args::ext_T::const_iterator it = args.extension().cbegin(); it != args.extension().cend(); ++it)
{
if (extension(d->path()) == *it)
{
++filesFound;
pool.callThread(d->path());
}
}
++d;
}
std::cout << "Scan Function: Calling TerminateThreads() " << std::endl;
pool.terminateThreads();
std::cout << "Scan Function: Called TerminateThreads() " << std::endl;
return filesFound;
}
Ill repeat the question again: What can I do to halt the main thread until worker threads have finished?
I don't get the issue with thread termination and join.
Joining threads is all about waiting until the given thread has terminated, so it's exaclty what you want to do. If the thread has finished execution already, join will just return immediately.
So you'll just want to join each thread during the terminate call as you already do in your code.
Note: currently you immediately rethrow any exception if a thread you just terminated has an active exception_ptr. That might lead to unjoined threads. You'll have to keep that in mind when handling those exceptions
Update: after looking at your code, I see a potential bug: std::condition_variable::wait() can return when a spurious wakeup occurs. If that is the case, you will work again on the path that was worked on the last time, leading to wrong results. You should have a flag for new work that is set if new work has been added, and that _threadCond.wait(lock) line should be in a loop that checks for the flag and _terminate. Not sure if that one will fix your problem, though.
The problem was two fold:
synchronizeStartingThreads() would sometimes have 1 or 2 threads blocked, waiting for the okay to go ahead (a problem in the while (some_condition) barrierCond.wait(lock). The condition would sometimes never evaluate to true. removing the while loop fixed this blocking issue.
The second issue was the potential for a worker thread to enter the _threadMtx, and notify_all was called just before they entered the _threadCond.wait(), since notify was already called, the thread would wait forever.
ie.
{
// terminate() is called
std::unique_lock<std::mutex> lock(_threadMtx);
// _threadCond.notify_all() is called here
_busy = false;
_threadCond.wait(lock);
// thread is blocked forever
}
surprisingly, locking this mutex in terminate() did not stop this from happening.
This was solved by adding a timeout of 30ms to the _threadCond.wait()
Also, a check was added before the starting of task to make sure the same task wasn't being processed again.
The new code now looks like this:
thisWorkerThread
_threadCond.wait_for(lock, std::chrono::milliseconds(30)); // hold the lock a max of 30ms
// after the lock, and the termination check
if(_busy)
{
Global::mFile_t rMap = _thisPool->_task(_pPath, *_pArgs, _thisPool->coutMatch_mtx);
_workerMap.element.insert(rMap.element.begin(), rMap.element.end());
}