Is it safe to wrap std::async in object - c++

I wrapped std::async in a class similar to this:
class AsyncTask
{
public:
AsyncTask() {}
~AsyncTask()
{
m_shouldTerminate.store(true, std::memory_order::memory_order_release);
}
std::future<int> runAsync()
{
return std::async(std::launch::async, [this]() { threadMain(); return m_result; });
}
private:
void threadMain()
{
for(int i=0; i<std::numeric_limits<int>::max(); ++i)
{
if (m_shouldTerminate.load(std::memory_order::memory_order_acquire))
{
break;
}
// do time consuming calculation but abort if m_shouldTerminate becomes true
m_result += foo([this]() { return m_shouldTerminate.load(std::memory_order::memory_order_acquire); });
}
}
int m_result = 0;
std::atomic<bool> m_shouldTerminate = false;
};
AFAIK std::future::~future blocks if the future was returned from std::async. This would mean that for code like
{
AsyncTask myTask;
myTask.runAsync();
}
bar();
It would block in the temporary future's destructor, then destruct myTask and only then the call to bar() would happen. Considering this it should be ensured that the lifetime of any AsyncTask object exceeds the run time of the task itself and my implementation should be safe.
If AsyncTask is dynamically allocated this guarantee would no longer hold, obviously.
Are my assumptions correct an is my implementation safe? In particular is it possible that an AsyncTask object is destroyed while the async task is still running?

Related

Lifetime of std::promise and std::future

My code:
void job_function(std::promise<void>& p) {
do_it();
p.set_value();
}
void foo() {
std::promise<void> p;
auto* thread = new std::thread(job_function, p);
p.get_future().wait_for(std::chrono::seconds(1));
}
In this code, if the calling thread of foo only waits for 1 second until the future completes. It is quite possible that the actual job gets completed after the wait is over. In this scenario, p is destructed already so call to p.set_value will not work. I can create p on heap, but even in that case it should be deleted and which thread should delete p depends on order of job completion and wait_for. Is there a specific pattern that can be used to handle this?
The trick is to move the promise into the thread and only keep the future around. Also, if you don't want to wait for the thread, detach it.
void job_function(std::promise<void> p) {
do_it();
p.set_value();
}
void foo() {
std::promise<void> p;
std::future<void> f = p.get_future();
std::thread thread(job_function, std::move(p));
thread.detach();
f.wait_for(std::chrono::seconds(1));
}
You are reimplementing std::packaged_task. Your code could be:
void job_function() {
do_it();
}
void foo() {
std::packaged_task<void(void)> task(job_function);
std::future result = task.get_future();
std::thread task_td(std::move(task));
result.wait_for(std::chrono::seconds(1));
}
shared_ptr to the rescue
void job_function(std::shared_ptr<std::promise> p) {
do_it();
p->set_value();
}
void foo() {
std::shared_ptr<std::promise> spPromise = std::make_shared<std::promise>();
auto* thread = new std::thread(job_function, spPromise);
spPromise->get_future().wait_for(std::chrono::seconds(1));
}
Now it doesn't matter if the thread completes before or after the original function that waits returns. The promise objects gets deleted when the last instance of the shared_ptr goes away.
If you want to keep the pass by reference semantics, just keep the shared_ptr captured by value for the lifetime of the thread.
void job_function(std::promise>& p) {
do_it();
p.set_value();
}
void foo() {
std::shared_ptr<std::promise> spPromise = std::make_shared<std::promise>();
std::promise& p = *spPromise.get();
auto* thread = new std::thread([spPromise] {
job_function(*spPromise.get()); // same as job_function(p)
});
p.get_future().wait_for(std::chrono::seconds(1));
}

Thread-safe locking of instance with multiple member functions

I have a struct instance that gets used by multiple threads. Each thread contains an unknown amount of function calls that alter the struct member variable.
I have a dedicated function that tries to "reserve" the struct instance for the current thread and I would like to ensure no other thread can reserve the instance till the original thread allows it.
Mutexes come to mind as those can be used to guard resources, but I only know of std::lock_guard that are in the scope of a single function, but do not add protection for all function calls in between lock and unlock.
Is it possible to protect a resource like that, when I know it will always call reserve and release in that order?
Snippet that explains it better:
#include <iostream> // std::cout
#include <thread> // std::thread
#include <mutex> // std::mutex
struct information_t {
std::mutex mtx;
int importantValue = 0;
// These should only be callable from the thread that currently holds the mutex
void incrementIt() { importantValue++; }
void decrementIt() { importantValue--; }
void reset() { importantValue = 0; }
} protectedResource; // We only have one instance of this that we need to work with
// Free the resource so other threads can reserve and use it
void release()
{
std::cout << "Result: " << protectedResource.importantValue << '\n';
protectedResource.reset();
protectedResource.mtx.unlock(); // Will this work? Can I guarantee the mtx is locked?
}
// Supposed to make sure no other thread can reserve or use it now anymore!
void reserve()
{
protectedResource.mtx.lock();
}
int main()
{
std::thread threads[3];
threads[0] = std::thread([]
{
reserve();
protectedResource.incrementIt();
protectedResource.incrementIt();
release();
});
threads[1] = std::thread([]
{
reserve();
// do nothing
release();
});
threads[2] = std::thread([]
{
reserve();
protectedResource.decrementIt();
release();
});
for (auto& th : threads) th.join();
return 0;
}
My suggestion per comment:
A better idiom might be a monitor which keeps the lock of your resource and provides access to the owner. To obtain a resource, the reserve() could return such monitor object (something like a proxy to access the contents of the resource). Any competing access to reserve() would block now (as the mutex is locked). When the resource owning thread is done, it just destroys the monitor object which in turn unlocks the resource. (This allows to apply RAII to all this which makes your code safe and maintainable.)
I modified OPs code to sketch how this could look like:
#include <iostream> // std::cout
#include <thread> // std::thread
#include <mutex> // std::mutex
class information_t {
private:
std::mutex mtx;
int importantValue = 0;
public:
class Monitor {
private:
information_t& resource;
std::lock_guard<std::mutex> lock;
friend class information_t; // to allow access to constructor.
private:
Monitor(information_t& resource):
resource(resource), lock(resource.mtx)
{ }
public:
~Monitor()
{
std::cout << "Result: " << resource.importantValue << '\n';
resource.reset();
}
Monitor(const Monitor&) = delete; // copying prohibited
Monitor& operator=(const Monitor&) = delete; // copy assign prohibited
public:
// exposed resource API for monitor owner:
void incrementIt() { resource.incrementIt(); }
void decrementIt() { resource.decrementIt(); }
void reset() { resource.reset(); }
};
friend class Monitor; // to allow access to private members
public:
Monitor aquire() { return Monitor(*this); }
private:
// These should only be callable from the thread that currently holds the mutex
// Hence, they are private and accessible through a monitor instance only
void incrementIt() { importantValue++; }
void decrementIt() { importantValue--; }
void reset() { importantValue = 0; }
} protectedResource; // We only have one instance of this that we need to work with
#if 0 // OBSOLETE
// Free the resource so other threads can reserve and use it
void release()
{
protectedResource.reset();
protectedResource.mtx.unlock(); // Will this work? Can I guarantee the mtx is locked?
}
#endif // 0
// Supposed to make sure no other thread can reserve or use it now anymore!
information_t::Monitor reserve()
{
return protectedResource.aquire();
}
using MyResource = information_t::Monitor;
int main()
{
std::thread threads[3];
threads[0]
= std::thread([]
{
MyResource protectedResource = reserve();
protectedResource.incrementIt();
protectedResource.incrementIt();
// scope end releases protectedResource
});
threads[1]
= std::thread([]
{
try {
MyResource protectedResource = reserve();
throw "Haha!";
protectedResource.incrementIt();
// scope end releases protectedResource
} catch(...) { }
});
threads[2]
= std::thread([]
{
MyResource protectedResource = reserve();
protectedResource.decrementIt();
// scope end releases protectedResource
});
for (auto& th : threads) th.join();
return 0;
}
Output:
Result: 2
Result: -1
Result: 0
Live Demo on coliru
Is it possible to protect a resource like that, when I know it will always call reserve and release in that order?
It's not anymore necessary to be concerned about this. The correct usage is burnt in:
To get access to the resource, you need a monitor.
If you get it you are the exclusive owner of the resource.
If you exit the scope (where you stored the monitor as local variable) the monitor is destroyed and thus the locked resource auto-released.
The latter will happen even for unexpected bail-outs (in the MCVE the throw "Haha!";).
Furthermore, I made the following functions private:
information_t::increment()
information_t::decrement()
information_t::reset()
So, no unauthorized access is possible. To use them properly, an information_t::Monitor instance must be acquired. It provides public wrappers to those functions which can be used in the scope where the monitor resides i.e. by the owner thread only.

What is the correct way of freeing std::thread* heap allocated memory?

I'm declaring a pointer to a thread in my class.
class A{
std::thread* m_pThread;
bool StartThread();
UINT DisableThread();
}
Here is how I call a function using a thread.
bool A::StartThread()
{
bool mThreadSuccess = false;
{
try {
m_pThread= new std::thread(&A::DisableThread, this);
mThreadSuccess = true;
}
catch (...) {
m_pDisable = false;
}
if(m_pThread)
{
m_pThread= nullptr;
}
}
return mThreadSuccess;
}
Here is the function called by my thread spawned.
UINT A::DisableThread()
{
//print something here.
return 0;
}
If I call this StartThread() function 10 times. Will it have a memory leak?
for (i = 0; i<10; i++){
bool sResult = StartThread();
if (sResult) {
m_pAcceptStarted = true;
}
}
What is the correct way of freeing
m_pThread= new std::thread(&A::DisableThread, this);
The correct way to free a non-array object created using allocating new is to use delete.
Avoid bare owning pointers and avoid unnecessary dynamic allocation. The example doesn't demonstrate any need for dynamic storage, and ideally you should use a std::thread member instead of a pointer.
If I call this StartThread() function 10 times. Will it have a memory leak?
Even a single call will result in a memory leak. The leak happens when you throw away the pointer value here:
m_pThread= nullptr;
could you add your better solution
Here's one:
auto future = std::async(std::launch::async, &A::DisableThread, this);
// do something while the other task executes in another thread
do_something();
// wait for the thread to finish and get the value returned by A::DisableThread
return future.get()
I'd personally would prefer using a threadpool in a real project but this example should give you an idea of how you could handle threads without new/delete.
#include <iostream>
#include <thread>
#include <vector>
class A
{
public:
template<typename Fn>
void CallAsync(Fn fn)
{
// put thread in vector
m_threads.emplace_back(std::thread(fn));
}
~A()
{
for (auto& thread : m_threads)
{
thread.join();
}
}
void someHandler()
{
std::cout << "*";
};
private:
std::vector<std::thread> m_threads;
};
int main()
{
A a;
for (int i = 0; i < 10; ++i)
{
a.CallAsync([&a] { a.someHandler(); });
}
}

Thread-safe reference-counted queue C++

I'm struggling to implement a thread-safe reference-counted queue. The idea is that I have a number of tasks that each maintain a shared_ptr to a task manager that owns the queue. Here is a minimal implementation that should encounter that same issue:
#include <condition_variable>
#include <deque>
#include <functional>
#include <iostream>
#include <memory>
#include <mutex>
#include <thread>
namespace {
class TaskManager;
struct Task {
std::function<void()> f;
std::shared_ptr<TaskManager> manager;
};
class Queue {
public:
Queue()
: _queue()
, _mutex()
, _cv()
, _running(true)
, _thread([this]() { sweepQueue(); })
{
}
~Queue() { close(); }
void close() noexcept
{
try {
{
std::lock_guard<std::mutex> lock(_mutex);
if (!_running) {
return;
}
_running = false;
}
_cv.notify_one();
_thread.join();
} catch (...) {
std::cerr << "An error occurred while closing the queue\n";
}
}
void push(Task&& task)
{
std::unique_lock<std::mutex> lock(_mutex);
_queue.emplace_back(std::move(task));
lock.unlock();
_cv.notify_one();
}
private:
void sweepQueue() noexcept
{
while (true) {
try {
std::unique_lock<std::mutex> lock(_mutex);
_cv.wait(lock, [this] { return !_running || !_queue.empty(); });
if (!_running && _queue.empty()) {
return;
}
if (!_queue.empty()) {
const auto task = _queue.front();
_queue.pop_front();
task.f();
}
} catch (...) {
std::cerr << "An error occurred while sweeping the queue\n";
}
}
}
std::deque<Task> _queue;
std::mutex _mutex;
std::condition_variable _cv;
bool _running;
std::thread _thread;
};
class TaskManager : public std::enable_shared_from_this<TaskManager> {
public:
void addTask(std::function<void()> f)
{
_queue.push({ f, shared_from_this() });
}
private:
Queue _queue;
};
} // anonymous namespace
int main(void)
{
const auto manager = std::make_shared<TaskManager>();
manager->addTask([]() { std::cout << "Hello world\n"; });
}
The problem I find is that on rare occasions, the queue will try to invoke its own destructor within the sweepQueue method. Upon further inspection, it seems that the reference count on the TaskManager hits zero once the last task is dequeued. How can I safely maintain the reference count without invoking the destructor?
Update: The example does not clarify the need for the std::shared_ptr<TaskManager> within Task. Here is an example use case that should illustrate the need for this seemingly unnecessary ownership cycle.
std::unique_ptr<Task> task;
{
const auto manager = std::make_shared<TaskManager>();
task = std::make_unique<Task>(someFunc, manager);
}
// Guarantees manager is not destroyed while task is still in scope.
The ownership hierarchy here is TaskManager owns Queue and Queue owns Tasks. Tasks maintaining a shared pointer to TaskManager create an ownership cycle which does not seem to serve a useful purpose here.
This is the ownership what is root of the problem here. A Queue is owned by TaskManager, so that Queue can have a plain pointer to TaskManager and pass that pointer to Task in sweepQueue. You do not need std::shared_pointer<TaskManager> in Task at all here.
I'd refactor the queue from the thread first.
But to fix your problem:
struct am_I_alive {
explicit operator bool() const { return m_ptr.lock(); }
private:
std::weak_ptr<void> m_ptr;
};
struct lifetime_tracker {
am_I_alive track_lifetime() {
if (!m_ptr) m_ptr = std::make_shared<bool>(true);
return {m_ptr};
}
lifetime_tracker() = default;
lifetime_tracker(lifetime_tracker const&) {} // do nothing, don't copy
lifetime_tracker& operator=(lifetime_tracker const&){ return *this; }
private:
std::shared_ptr<void> m_ptr;
};
this is a little utility to detect if we have been deleted. It is useful in any code that calls an arbitrary callback whose side effect could include delete(this).
Privately inherit your Queue from it.
Then split popping the task from running it.
std::optional<Task> get_task() {
std::unique_lock<std::mutex> lock(_mutex);
_cv.wait(lock, [this] { return !_running || !_queue.empty(); });
if (!_running && _queue.empty()) {
return {}; // end
}
auto task = _queue.front();
_queue.pop_front();
return task;
}
void sweepQueue() noexcept
{
while (true) {
try {
auto task = get_task();
if (!task) return;
// we are alive here
auto alive = track_lifetime();
try {
(*task).f();
} catch(...) {
std::cerr << "An error occurred while running a task\n";
}
task={};
// we could be deleted here
if (!alive)
return; // this was deleted, get out of here
}
} catch (...) {
std::cerr << "An error occurred while sweeping the queue\n";
}
}
}
and now you are safe.
After that you need to deal with the thread problem.
The thread problem is that you need your code to destroy the thread from within the thread it is running. At the same time, you also need to guarantee that the thread has terminated before main ends.
These are not compatible.
To fix that, you need to create a thread owning pool that doesn't have your "keep alive" semantics, and get your thread from there.
These threads don't delete themselves; instead, they return themselves to that pool for reuse by another client.
At shutdown, those threads are blocked on to ensure you don't have code running elsewhere that hasn't halted before the end of main.
To write such a pool without your inverted dependency mess, split the queue part of your code off. This queue owns no thread.
template<class T>
struct threadsafe_queue {
void push(T);
std::optional<T> pop(); // returns empty if thread is aborted
void abort();
~threadsafe_queue();
private:
std::mutex m;
std::condition_variable v;
std::deque<T> data;
bool aborted = false;
};
then a simple thread pool:
struct thread_pool {
template<class F>
std::future<std::result_of_t<F&()>> enqueue( F&& f );
template<class F>
std::future<std::result_of_t<F&()>> thread_off_now( F&& f ); // starts a thread if there aren't any free
void abort();
void start_thread( std::size_t n = 1 );
std::size_t count_threads() const;
~thread_pool();
private:
threadsafe_queue< std::function<void()> > tasks;
std::vector< std::thread > threads;
static void thread_loop( thread_pool* pool );
};
make a thread pool singleton. Get your threads for your queue from thread_off_now method, guaranteeing you a thread that (when you are done with it) can be recycled, and whose lifetime is handled by someone else.
But really, you should instead be thinking with ownership in mind. The idea that tasks and task queues mutually own each other is a mess.
If someone disposes of a task queue, it is probably a good idea to abandon the tasks instead of persisting it magically and silently.
Which is what my simple thread pool does.

Assignment within RAII scope

Problem
How do you initialize an object inside a RAII scope, and use it outside of that scope?
Background
I have a global lock which can be called with lock() and unlock().
I have a type, LockedObject, which can only be initialized when the global lock is locked.
I have a function, use_locked(LockedObject &locked_object), which needs to be called with the global lock unlocked.
The usage scenario is
lock();
LockedObject locked_object;
unlock();
use_locked(locked_object);
RAII
For various reasons, I moved to a RAII encapsulation of the global lock. I would like to use this everywhere, primarily as creating LockedObject can fail with exceptions.
The problem is that
{
GlobalLock global_lock;
LockedObject locked_object;
}
use_locked(locked_object);
fails, as locked_object is created in the inner scope.
Examples
Set-up (mostly not important):
#include <assert.h>
#include <iostream>
bool locked = false;
void lock() {
assert(!locked);
locked = true;
}
void unlock() {
assert(locked);
locked = false;
}
class LockedObject {
public:
LockedObject(int i) {
assert(locked);
std::cout << "Initialized: " << i << std::endl;
}
};
void use_locked(LockedObject locked_object) {
assert(!locked);
}
class GlobalLock {
public:
GlobalLock() {
lock();
}
~GlobalLock() {
unlock();
}
};
Original, non RAII method:
void manual() {
lock();
LockedObject locked_object(123);
unlock();
use_locked(locked_object);
}
Broken RAII methods:
/*
void raii_broken_scoping() {
{
GlobalLock global_lock;
// Initialized in the wrong scope
LockedObject locked_object(123);
}
use_locked(locked_object);
}
*/
/*
void raii_broken_initialization() {
// No empty initialization
// Alternatively, empty initialization requires lock
LockedObject locked_object;
{
GlobalLock global_lock;
locked_object = LockedObject(123);
}
use_locked(locked_object);
}
*/
And a main function:
int main(int, char **) {
manual();
// raii_broken_scoping();
// raii_broken_initialization;
}
For what it's worth, in Python I would do:
with GlobalLock():
locked_object = LockedObject(123)
I want the equivalent of that. I mention my current solution in an answer, but it feels clumsy.
The specific (but simplified) code to be executed follows. With my current lambda-based call:
boost::python::api::object wrapped_object = [&c_object] () {
GIL lock_gil;
return boost::python::api::object(boost::ref(c_object));
} ();
auto thread = std::thread(use_wrapped_object, c_object);
with
class GIL {
public:
GIL();
~GIL();
private:
GIL(const GIL&);
PyGILState_STATE gilstate;
};
GIL::GIL() {
gilstate = PyGILState_Ensure();
}
GIL::~GIL() {
PyGILState_Release(gilstate);
}
boost::python::api::objects must be created with the GIL and the thread must be created without the GIL. The PyGILState struct and function calls are all given to me by CPython's C API, so I can only wrap them.
Allocate your object on the heap and use some pointers:
std::unique_ptr<LockedObject> locked_object;
{
GlobalLock global_lock;
locked_object.reset(new LockedObject());
}
use_locked(locked_object);
Here is a complete list of options from my perspective. optional would be what I would do:
The proposed post-C++1y optional would solve your problem, as it lets you construct data after declaration, as would heap based unique_ptr solutions. Roll your own, or steal ot from boost
A 'run at end of scope' RAII function storer (with 'commit') can also make this code less crazy, as can letting your locks be manually disengaged within their scope.
template<class F>
struct run_at_end_of_scope {
F f;
bool Skip;
void commit(){ if (!Skip) f(); Skip = true; }
void skip() { Skip = true; }
~run_at_end_of_scope(){commit();}
};
template<class F>
run_at_end_of_scope<F> at_end(F&&f){ return {std::forward<F>(f), false}; }
then:
auto later = at_end([&]{ /*code*/ });
and you can later.commit(); or later.skip(); to run the code earlier or skip running it.
Making your RAII locking classes have move constructors would let you do construction in another scope, and return via move (possibly elided).
LockedObject make_LockedObject(){
GlobalLock lock;
return {};
}
My current solution is to use an anonymous function:
void raii_return() {
LockedObject locked_object = [&] () {
GlobalLock global_lock;
return LockedObject(123);
} ();
use_locked(locked_object);
}
The advantage of this approach is that it avoids pointers and thanks to copy elision it should be quite fast.
One downside is that LockedObjects don't necessarily support copying (use_locked would in that case take a reference).