unique_ptr with multithreading - c++

I have some fear about using unique_ptr with multithreading without mutex. I wrote simplified code below, please take a look. If I check unique_ptr != nullptr, is it thread safe?
class BigClassCreatedOnce
{
public:
std::atomic<bool> var;
// A lot of other stuff
};
BigClassCreatedOnce class instance will be created only once but I'm not sure is it safe to use it between threads.
class MainClass
{
public:
// m_bigClass used all around the class from the Main Thread
MainClass()
: m_bigClass()
, m_thread()
{
m_thread = std::thread([this]() {
while (1)
{
methodToBeCalledFromThread();
std::this_thread::sleep_for(std::chrono::milliseconds(1));
}
});
// other stuff here
m_bigClass.reset(new BigClassCreatedOnce()); // created only once
}
void methodToBeCalledFromThread()
{
if (!m_bigClass) // As I understand this is not safe
{
return;
}
if (m_bigClass->var.load()) // As I understand this is safe
{
// does something
}
}
std::unique_ptr<BigClassCreatedOnce> m_bigClass;
std::thread m_thread;
};
I just put it into infinity loop to simplify the sample.
int main()
{
MainClass ms;
while (1)
{
std::this_thread::sleep_for(std::chrono::milliseconds(1));
}
}

If I check unique_ptr != nullptr, is it thread safe
No, it is not thread safe. If you have more than one thread and at least of one of them writes to the shared data then you need synchronization. If you do not then you have a data race and it is undefined behavior.
m_bigClass.reset(new BigClassCreatedOnce()); // created only once
and
if (!m_bigClass)
Can both happen at the same time, so it is a data race.
I would also like to point out that
if (m_bigClass->var.load())
Is also not thread safe. var.load() is, but the access of m_bigClass is not so you could also have a data race there.

Related

C++20 stopping a detached std::jthread using an std::stop_token

In C++20 std::jthread was introduced as a safer version of std::thread; where std::jthread, as far as I understand, cleans up after itself when the thread exits.
Also, the concept of cooperative cancellation is introduced such that an std::jthread manages an std::stop_source that handles the state of the underlying thread, this std::stop_source exposes an std::stop_token that outsiders can use to read the state of the thread sanely.
What I have is something like this.
class foo {
std::stop_token stok;
std::stop_source ssource;
public:
void start_foo() {
// ...
auto calculation = [this](std::stop_token inner_tok) {
// ... (*this is used here)
while(!inner_tok.stop_requested()) {
// stuff
}
}
auto thread = std::jthread(calculation);
ctok = thread.get_stop_token();
ssource = thread.get_stop_source();
thread.detach(); // ??
}
void stop_foo() {
if (ssource.stop_possible()) {
ssource.request_stop();
}
}
~foo() {
stop_foo();
}
}
Note foo is managed by a std::shared_ptr, and there is no public constructor.
Somewhere along the line, another thread can call foo::stop_foo() on a possibly detached thread.
Is what I am doing safe?
Also, when detaching a thread, the C++ handle is no longer associated with the running thread, and the OS manages it, but does the thread keep receiving stop notifications from the std::stop_source?
Is there a better way to achieve what I need? In MVSC, this doesn't seem to raise any exceptions or halt program execution, and I've done a lot of testing to verify this.
So, is this solution portable?
What you wrote is potentially unsafe if the thread accesses this after the foo has been destroyed. It's also a bit convoluted. A simpler approach would just be to stick the jthread in the structure...
class foo {
std::jthread thr;
public:
void start_foo() {
// ...
jthr = std::jthread([this](std::stop_token inner_tok) {
// ... (*this is used here)
while(!inner_tok.stop_requested()) {
// stuff
}
});
}
void stop_foo() {
jthr.request_stop();
}
~foo() {
stop_foo();
// jthr.detatch(); // this is a bad idea
}
}
To match the semantics of your code, you would uncomment the jthr.detach() in the destructor, but this is actually a bad idea since then you could end up destroying foo while the thread is still accessing it. The code I wrote above is safe, but obviously whichever thread drops the last reference to the foo will have to wait for the jthread to exit. If that's really intolerable, then maybe you want to change the API to stick a shared_ptr in the thread itself, so that the thread can destroy foo if it is still running after the last external reference is dropped.

Is there a way to protect a smart pointer from being deallocated on one thread, when work is being done on another thread?

In our program, we have a class FooLogger which logs specific events (strings). We use the FooLogger as a unique_ptr.
We have two threads which use this unique_ptr instance:
Thread 1 logs the latest event to file in a while loop, first checking if the instance is not nullptr
Thread 2 deallocates the FooLogger unique_ptr instance when the program has reached a certain point (set to nullptr)
However, due to bad interleaving, it is possible that, while logging, the member variables of FooLogger are deallocated, resulting in an EXC_BAD_ACCESS error.
class FooLogger {
public:
FooLogger() {};
void Log(const std::string& event="") {
const float32_t time_step_s = timer_.Elapsed() - runtime_s_; // Can get EXC_BAD_ACCESS on timer_
runtime_s_ += time_step_s;
std::cout << time_step_s << runtime_s_ << event << std::endl;
}
private:
Timer timer_; // Timer is a custom class
float32_t runtime_s_ = 0.0;
};
int main() {
auto foo_logger = std::make_unique<FooLogger>();
std::thread foo_logger_thread([&] {
while(true) {
if (foo_logger)
foo_logger->Log("some event");
else
break;
}
});
SleepMs(50); // pseudo code
foo_logger = nullptr;
foo_logger_thread.join();
}
Is it possible, using some sort of thread synchronisation/locks etc. to ensure that the foo_logger instance is not deallocated while logging? If not, are there any good ways of handling this case?
The purpose of std::unique_ptr is to deallocate the instance once std::unique_ptr is out of scope. In your case, you have multiple threads each having access to the element and the owning thread might get eliminated prior to other users.
You either need to ensure that owner thread never gets deleted prior to the user threads or change ownership model from std::unique_ptr to std::shared_ptr. It is the whole purpose of std::shared_ptr to ensure that the object is alive as long as you use it.
You just need to figure out what's required for program and use the right tools to achieve it.
Use a different mechanism than the disappearance of an object for determining when to stop.
(When you use a single thing for two separate purposes, you often get into trouble.)
For instance, an atomic bool:
int main() {
FooLogger foo_logger;
std::atomic<bool> keep_going = true;
std::thread foo_logger_thread([&] {
while(keep_going) {
foo_logger.Log("some event");
}
});
SleepMs(50);
keep_going = false;
foo_logger_thread.join();
}
It sounds like std::weak_ptr can help in this case.
You can make one from a std::shared_ptr and pass it to the logger thread.
For example:
class FooLogger {
public:
void Log(std::string const& event) {
// log the event ...
}
};
int main() {
auto shared_logger = std::make_shared<FooLogger>();
std::thread foo_logger_thread([w_logger = std::weak_ptr(shared_logger)]{
while (true) {
auto logger = w_logger.lock();
if (logger)
logger->Log("some event");
else
break;
}
});
// some work ...
shared_logger.reset();
foo_logger_thread.join();
}
Use should use make_shared instead of make_unique. And change:
std::thread foo_logger_thread([&] {
to
std::thread foo_logger_thread([foo_logger] {
It will create new instance of shared_ptr.

Best way to handle multi-thread cleanup

I have a server-type application, and I have an issue with making sure thread's aren't deleted before they complete. The code below pretty much represents my server; the cleanup is required to prevent a build up of dead threads in the list.
using namespace std;
class A {
public:
void doSomethingThreaded(function<void()> cleanupFunction, function<bool()> getStopFlag) {
somethingThread = thread([cleanupFunction, getStopFlag, this]() {
doSomething(getStopFlag);
cleanupFunction();
});
}
private:
void doSomething(function<bool()> getStopFlag);
thread somethingThread;
...
}
class B {
public:
void runServer();
void stop() {
stopFlag = true;
waitForListToBeEmpty();
}
private:
void waitForListToBeEmpty() { ... };
void handleAccept(...) {
shared_ptr<A> newClient(new A());
{
unique_lock<mutex> lock(listMutex);
clientData.push_back(newClient);
}
newClient.doSomethingThreaded(bind(&B::cleanup, this, newClient), [this]() {
return stopFlag;
});
}
void cleanup(shared_ptr<A> data) {
unique_lock<mutex> lock(listMutex);
clientData.remove(data);
}
list<shared_ptr<A>> clientData;
mutex listMutex;
atomc<bool> stopFlag;
}
The issue seems to be that the destructors run in the wrong order - i.e. the shared_ptr is destructed at when the thread's function completes, meaning the 'A' object is deleted before thread completion, causing havok when the thread's destructor is called.
i.e.
Call cleanup function
All references to this (i.e. an A object) removed, so call destructor (including this thread's destructor)
Call this thread's destructor again -- OH NOES!
I've looked at alternatives, such as maintaining a 'to be removed' list which is periodically used to clean the primary list by another thread, or using a time-delayed deletor function for the shared pointers, but both of these seem abit chunky and could have race conditions.
Anyone know of a good way to do this? I can't see an easy way of refactoring it to work ok.
Are the threads joinable or detached? I don't see any detach,
which means that destructing the thread object without having
joined it is a fatal error. You might try simply detaching it,
although this can make a clean shutdown somewhat complex. (Of
course, for a lot of servers, there should never be a shutdown
anyway.) Otherwise: what I've done in the past is to create
a reaper thread; a thread which does nothing but join any
outstanding threads, to clean up after them.
I might add that this is a good example of a case where
shared_ptr is not appropriate. You want full control over
when the delete occurs; if you detach, you can do it in the
clean up function (but quite frankly, just using delete this;
at the end of the lambda in A::doSomethingThreaded seems more
readable); otherwise, you do it after you've joined, in the
reaper thread.
EDIT:
For the reaper thread, something like the following should work:
class ReaperQueue
{
std::deque<A*> myQueue;
std::mutex myMutex;
std::conditional_variable myCond;
A* getOne()
{
std::lock<std::mutex> lock( myMutex );
myCond.wait( lock, [&]( !myQueue.empty() ) );
A* results = myQueue.front();
myQueue.pop_front();
return results;
}
public:
void readyToReap( A* finished_thread )
{
std::unique_lock<std::mutex> lock( myMutex );
myQueue.push_back( finished_thread );
myCond.notify_all();
}
void reaperThread()
{
for ( ; ; )
{
A* mine = getOne();
mine->somethingThread.join();
delete mine;
}
}
};
(Warning: I've not tested this, and I've tried to use the C++11
functionality. I've only actually implemented it, in the past,
using pthreads, so there could be some errors. The basic
principles should hold, however.)
To use, create an instance, then start a thread calling
reaperThread on it. In the cleanup of each thread, call
readyToReap.
To support a clean shutdown, you may want to use two queues: you
insert each thread into the first, as it is created, and then
move it from the first to the second (which would correspond to
myQueue, above) in readyToReap. To shut down, you then wait
until both queues are empty (not starting any new threads in
this interval, of course).
The issue is that, since you manage A via shared pointers, the this pointer captured by the thread lambda really needs to be a shared pointer rather than a raw pointer to prevent it from becoming dangling. The problem is that there's no easy way to create a shared_ptr from a raw pointer when you don't have an actual shared_ptr as well.
One way to get around this is to use shared_from_this:
class A : public enable_shared_from_this<A> {
public:
void doSomethingThreaded(function<void()> cleanupFunction, function<bool()> getStopFlag) {
somethingThread = thread([cleanupFunction, getStopFlag, this]() {
shared_ptr<A> temp = shared_from_this();
doSomething(getStopFlag);
cleanupFunction();
});
this creates an extra shared_ptr to the A object that keeps it alive until the thread finishes.
Note that you still have the problem with join/detach that James Kanze identified -- Every thread must have either join or detach called on it exactly once before it is destroyed. You can fulfill that requirement by adding a detach call to the thread lambda if you never care about the thread exit value.
You also have potential for problems if doSomethingThreaded is called multiple times on a single A object...
For those who are interested, I took abit of both answers given (i.e. James' detach suggestion, and Chris' suggestion about shared_ptr's).
My resultant code looks like this and seems neater and doesn't cause a crash on shutdown or client disconnect:
using namespace std;
class A {
public:
void doSomething(function<bool()> getStopFlag) {
...
}
private:
...
}
class B {
public:
void runServer();
void stop() {
stopFlag = true;
waitForListToBeEmpty();
}
private:
void waitForListToBeEmpty() { ... };
void handleAccept(...) {
shared_ptr<A> newClient(new A());
{
unique_lock<mutex> lock(listMutex);
clientData.push_back(newClient);
}
thread clientThread([this, newClient]() {
// Capture the shared_ptr until thread over and done with.
newClient->doSomething([this]() {
return stopFlag;
});
cleanup(newClient);
});
// Detach to remove the need to store these threads until their completion.
clientThread.detach();
}
void cleanup(shared_ptr<A> data) {
unique_lock<mutex> lock(listMutex);
clientData.remove(data);
}
list<shared_ptr<A>> clientData; // Can remove this if you don't
// need to connect with your clients.
// However, you'd need to make sure this
// didn't get deallocated before all clients
// finished as they reference the boolean stopFlag
// OR make it a shared_ptr to an atomic boolean
mutex listMutex;
atomc<bool> stopFlag;
}

how to let a thread wait for destruction of an object

I want to have a thread wait for the destruction of a specific object by another thread. I thought about implementing it somehow like this:
class Foo {
private:
pthread_mutex_t* mutex;
pthread_cond_t* condition;
public:
Foo(pthread_mutex_t* _mutex, pthread_cond_t* _condition) : mutex(_mutex), condition(_condition) {}
void waitForDestruction(void) {
pthread_mutex_lock(mutex);
pthread_cond_wait(condition,mutex);
pthread_mutex_unlock(mutex);
}
~Foo(void) {
pthread_mutex_lock(mutex);
pthread_cond_signal(condition);
pthread_mutex_unlock(mutex);
}
};
I know, however, that i must handle spurious wakeups in the waitForDestruction method, but i can't call anything on 'this', because it could already be destructed.
Another possibility that crossed my mind was to not use a condition variable, but lock the mutex in the constructor, unlock it in the destructor and lock/unlock it in the waitForDestruction method - this should work with a non-recursive mutex, and iirc i can unlock a mutex from a thread which didn't lock it, right? Will the second option suffer from any spurious wakeups?
It is always a difficult matter. But how about these lines of code:
struct FooSync {
typedef boost::shared_ptr<FooSync> Ptr;
FooSync() : owner(boost::this_thread::get_id()) {
}
void Wait() {
assert(boost::this_thread::get_id() != owner);
mutex.lock();
mutex.unlock();
}
boost::mutex mutex;
boost::thread::id owner;
};
struct Foo {
Foo() { }
~Foo() {
for (size_t i = 0; i < waiters.size(); ++i) {
waiters[i]->mutex.unlock();
}
}
FooSync::Ptr GetSync() {
waiters.push_back(FooSync::Ptr(new FooSync));
waiters.back()->mutex.lock();
return waiters.back();
}
std::vector<FooSync::Ptr> waiters;
};
The solution above would allow any number of destruction-wait object on a single Foo object. As long as it will correctly manage memory occupied by these objects. It seems that nothing prevents Foo instances to be created on the stack.
Though the only drawback I see is that it requires that destruction-wait objects always created in a thread that "owns" Foo object instance otherwise the recursive lock will probably happen. There is more, if GetSync gets called from multiple threads race condition may occur after push_back.
EDIT:
Ok, i have reconsidered the problem and came up with new solution. Take a look:
typedef boost::shared_ptr<boost::shared_mutex> MutexPtr;
struct FooSync {
typedef boost::shared_ptr<FooSync> Ptr;
FooSync(MutexPtr const& ptr) : mutex(ptr) {
}
void Wait() {
mutex->lock_shared();
mutex->unlock_shared();
}
MutexPtr mutex;
};
struct Foo {
Foo() : mutex(new boost::shared_mutex) {
mutex->lock();
}
~Foo() {
mutex->unlock();
}
FooSync::Ptr GetSync() {
return FooSync::Ptr(new FooSync(mutex));
}
MutexPtr mutex;
};
Now it seems reasonably cleaner and much less points of code are subjects to race conditions. There is only one synchronization primitive shared between object itself and all the sync-objects. Some efforts must be taken to overcome the case when Wait called in the thread where the object itself is (like in my first example). If the target platform does not support shared_mutex it is ok to go along with good-ol mutex. shared_mutex seems to reduce the burden of locks when there are many of FooSyncs waiting.

C++ Critical Section not working

My critical section code does not work!!!
Backgrounder.run IS able to modify MESSAGE_QUEUE g_msgQueue and LockSections destructor hadn't been called yet !!!
Extra code :
typedef std::vector<int> MESSAGE_LIST; // SHARED OBJECT .. MUST LOCK!
class MESSAGE_QUEUE : MESSAGE_LIST{
public:
MESSAGE_LIST * m_pList;
MESSAGE_QUEUE(MESSAGE_LIST* pList){ m_pList = pList; }
~MESSAGE_QUEUE(){ }
/* This class will be shared between threads that means any
* attempt to access it MUST be inside a critical section.
*/
void Add( int messageCode ){ if(m_pList) m_pList->push_back(messageCode); }
int getLast()
{
if(m_pList){
if(m_pList->size() == 1){
Add(0x0);
}
m_pList->pop_back();
return m_pList->back();
}
}
void removeLast()
{
if(m_pList){
m_pList->erase(m_pList->end()-1,m_pList->end());
}
}
};
class Backgrounder{
public:
MESSAGE_QUEUE* m_pMsgQueue;
static void __cdecl Run( void* args){
MESSAGE_QUEUE* s_pMsgQueue = (MESSAGE_QUEUE*)args;
if(s_pMsgQueue->getLast() == 0x45)printf("It's a success!");
else printf("It's a trap!");
}
Backgrounder(MESSAGE_QUEUE* pMsgQueue)
{
m_pMsgQueue = pMsgQueue;
_beginthread(Run,0,(void*)m_pMsgQueue);
}
~Backgrounder(){ }
};
int main(){
MESSAGE_LIST g_List;
CriticalSection crt;
ErrorHandler err;
LockSection lc(&crt,&err); // Does not work , see question #2
MESSAGE_QUEUE g_msgQueue(&g_List);
g_msgQueue.Add(0x45);
printf("%d",g_msgQueue.getLast());
Backgrounder back_thread(&g_msgQueue);
while(!kbhit());
return 0;
}
#ifndef CRITICALSECTION_H
#define CRITICALSECTION_H
#include <windows.h>
#include "ErrorHandler.h"
class CriticalSection{
long m_nLockCount;
long m_nThreadId;
typedef CRITICAL_SECTION cs;
cs m_tCS;
public:
CriticalSection(){
::InitializeCriticalSection(&m_tCS);
m_nLockCount = 0;
m_nThreadId = 0;
}
~CriticalSection(){ ::DeleteCriticalSection(&m_tCS); }
void Enter(){ ::EnterCriticalSection(&m_tCS); }
void Leave(){ ::LeaveCriticalSection(&m_tCS); }
void Try();
};
class LockSection{
CriticalSection* m_pCS;
ErrorHandler * m_pErrorHandler;
bool m_bIsClosed;
public:
LockSection(CriticalSection* pCS,ErrorHandler* pErrorHandler){
m_bIsClosed = false;
m_pCS = pCS;
m_pErrorHandler = pErrorHandler;
// 0x1AE is code prefix for critical section header
if(!m_pCS)m_pErrorHandler->Add(0x1AE1);
if(m_pCS)m_pCS->Enter();
}
~LockSection(){
if(!m_pCS)m_pErrorHandler->Add(0x1AE2);
if(m_pCS && m_bIsClosed == false)m_pCS->Leave();
}
void ForceCSectionClose(){
if(!m_pCS)m_pErrorHandler->Add(0x1AE3);
if(m_pCS){m_pCS->Leave();m_bIsClosed = true;}
}
};
/*
Safe class basic structure;
class SafeObj
{
CriticalSection m_cs;
public:
void SafeMethod()
{
LockSection myLock(&m_cs);
//add code to implement the method ...
}
};
*/
#endif
Two questions in one. I don't know about the first, but the critical section part is easy to explain. The background thread isn't trying to claim the lock and so, of course, is not blocked. You need to make the critical section object crt visible to the thread so that it can lock it.
The way to use this lock class is that each section of code that you want serialised must create a LockSection object and hold on to it until the end of the serialised block:
Thread 1:
{
LockSection lc(&crt,&err);
//operate on shared object from thread 1
}
Thread 2:
{
LockSection lc(&crt,&err);
//operate on shared object from thread 2
}
Note that it has to be the same critical section instance crt that is used in each block of code that is to be serialised.
This code has a number of problems.
First of all, deriving from the standard containers is almost always a poor idea. In this case you're using private inheritance, which reduces the problems, but doesn't eliminate them entirely. In any case, you don't seem to put the inheritance to much (any?) use anyway. Even though you've derived your MESSAGE_QUEUE from MESSAGE_LIST (which is actually std::vector<int>), you embed a pointer to an instance of a MESSAGE_LIST into MESSAGE_QUEUE anyway.
Second, if you're going to use a queue to communicate between threads (which I think is generally a good idea) you should make the locking inherent in the queue operations rather than requiring each thread to manage the locking correctly on its own.
Third, a vector isn't a particularly suitable data structure for representing a queue anyway, unless you're going to make it fixed size, and use it roughly like a ring buffer. That's not a bad idea either, but it's quite a bit different from what you've done. If you're going to make the size dynamic, you'd probably be better off starting with a deque instead.
Fourth, the magic numbers in your error handling (0x1AE1, 0x1AE2, etc.) is quite opaque. At the very least, you need to give these meaningful names. The one comment you have does not make the use anywhere close to clear.
Finally, if you're going to go to all the trouble of writing code for a thread-safe queue, you might as well make it generic so it can hold essentially any kind of data you want, instead of dedicating it to one specific type.
Ultimately, your code doesn't seem to save the client much work or trouble over using the Windows functions directly. For the most part, you've just provided the same capabilities under slightly different names.
IMO, a thread-safe queue should handle almost all the work internally, so that client code can use it about like it would any other queue.
// Warning: untested code.
// Assumes: `T::T(T const &) throw()`
//
template <class T>
class queue {
std::deque<T> data;
CRITICAL_SECTION cs;
HANDLE semaphore;
public:
queue() {
InitializeCriticalSection(&cs);
semaphore = CreateSemaphore(NULL, 0, 2048, NULL);
}
~queue() {
DeleteCriticalSection(&cs);
CloseHandle(semaphore);
}
void push(T const &item) {
EnterCriticalSection(&cs);
data.push_back(item);
LeaveCriticalSection(&cs);
ReleaseSemaphore(semaphore, 1, NULL);
}
T pop() {
WaitForSingleObject(semaphore, INFINITE);
EnterCriticalSection(&cs);
T item = data.front();
data.pop_front();
LeaveCriticalSection(&cs);
return item;
}
};
HANDLE done;
typedef queue<int> msgQ;
enum commands { quit, print };
void backgrounder(void *qq) {
// I haven't quite puzzled out what your background thread
// was supposed to do, so I've kept it really simple, executing only
// the two commands listed above.
msgQ *q = (msgQ *)qq;
int command;
while (quit != (command = q->pop()))
printf("Print\n");
SetEvent(done);
}
int main() {
msgQ q;
done = CreateEvent(NULL, false, false, NULL);
_beginthread(backgrounder, 0, (void*)&q);
for (int i=0; i<20; i++)
q.push(print);
q.push(quit);
WaitForSingleObject(done, INFINITE);
return 0;
}
Your background thread needs access to the same CriticalSection object and it needs to create LockSection objects to lock it -- the locking is collaborative.
You are trying to return the last element after popping it.