I've passed a promise as a reference to a thread. Afterwards, the promise was moved into a vector via std::move. This is causing a segmentation fault when the software is executed.
I reckon the reference in the thread is never updated after moving the promise? How can I pass the promise to the thread so that I can move it afterwards? Please see the following code example of my problem.
#include <iostream>
#include <thread>
#include <vector>
#include <future>
class Test {
public:
std::thread t;
std::promise<int> p;
Test(std::thread&& rt, std::promise<int>&& rp) : t(std::move(rt)), p(std::move(rp)) {}
};
int main()
{
std::vector<Test> tests;
{
auto p = std::promise<int>();
std::thread t ([&p]{
std::cout << 1;
p.set_value(1);
});
tests.push_back(Test(std::move(t), std::move(p)));
}
for(Test& mytest : tests)
{
mytest.t.join();
}
}
The promise p that the lambda holds a reference to is moved from and goes out of scope. You'll need an extra level of indirection so that the promise never moves.
auto pp = std::make_unique<std::promise<int>>();
std::thread t ([p = pp.get()] { // <--- p is a promise<int>*
std::cout << 1;
p->set_value(1);
});
This way, the promise never moves, you just move the pointer. The lambda gets a regular non-owning pointer to the promise.
See it here.
I do not have an answer to your question. At least, I have none yet. However, no other answers seem to have appeared yet and I find your question is interesting, so let's try this:
#include <iostream>
#include <thread>
#include <vector>
#include <future>
#include <memory>
class Test {
public:
std::thread t;
std::unique_ptr<std::promise<int>> pp;
Test(std::thread&& rt, std::unique_ptr<std::promise<int>>&& rpp)
: t(std::move(rt)), pp(std::move(rpp)) {}
};
int main()
{
std::vector<Test> tests;
{
auto pp = std::make_unique<std::promise<int>>();
std::thread t ([&pp]{
std::cout << 1;
pp->set_value(1);
});
tests.push_back(Test(std::move(t), std::move(pp)));
}
for(Test& mytest : tests)
{
mytest.t.join();
}
}
Do you see what I did there? I indirected ownership of the promise through a smart pointer. We know that smart pointers destruct gracefully, so the promise itself is never moved by this code, but only the pointer to the promise is moved. Yet the code still segfaults.
So are we sure that the promise is actually what is causing the segfault?
Maybe the promise is indeed causing the segfault, but now at least we have another way to attack the problem—unless you have already tried this.
Related
I am new to boost:asio. I need to pass shared_ptr as argument to handler function.
E.g.
boost::asio::post(std::bind(&::function_x, std::move(some_shared_ptr)));
Is using std::move(some_shared_ptr) correct? or should I use as below,
boost::asio::post(std::bind(&::function_x, some_shared_ptr));
If both are correct, which one is advisable?
Thanks in advance
Regards
Shankar
Bind stores arguments by value.
So both are correct and probably equivalent. Moving the argument into the bind is potentially more efficient if some_argument is not gonna be used after the bind.
Warning: Advanced Use Cases
(just skip this if you want)
Not what you asked: what if function_x took rvalue-reference arguments?
Glad you asked. You can't. However, you can still receive by lvalue reference and just move from that. because:
std::move doesn't move
The rvalue-reference is only there to indicate potentially-moved-from arguments enabling some smart compiler optimizations and diagnostics.
So, as long as you know your bound function is only executed once (!!) then it's safe to move from lvalue parameters.
In the case of shared-pointers there's actually a little bit more leeway, because moving from the shared-ptr doesn't actually move the pointed-to element at all.
So, a little exercise demonstrating it all:
Live On Coliru
#include <boost/asio.hpp>
#include <memory>
#include <iostream>
static void foo(std::shared_ptr<int>& move_me) {
if (!move_me) {
std::cout << "already moved!\n";
} else {
std::cout << "argument: " << *std::move(move_me) << "\n";
move_me.reset();
}
}
int main() {
std::shared_ptr<int> arg = std::make_shared<int>(42);
std::weak_ptr<int> observer = std::weak_ptr(arg);
assert(observer.use_count() == 1);
auto f = std::bind(foo, std::move(arg));
assert(!arg); // moved
assert(observer.use_count() == 1); // so still 1 usage
{
boost::asio::io_context ctx;
post(ctx, f);
ctx.run();
}
assert(observer.use_count() == 1); // so still 1 usage
f(); // still has the shared arg
// but now the last copy was moved from, so it's gone
assert(observer.use_count() == 0); //
f(); // already moved!
}
Prints
argument: 42
argument: 42
already moved!
Why Bother?
Why would you care about the above? Well, since in Asio you have a lot of handlers that are guaranteed to execute precisely ONCE, you can sometimes avoid the overhead of shared pointers (the synchronization, the allocation of the control block, the type erasure of the deleter).
That is, you can use move-only handlers using std::unique_ptr<>:
Live On Coliru
#include <boost/asio.hpp>
#include <memory>
#include <iostream>
static void foo(std::unique_ptr<int>& move_me) {
if (!move_me) {
std::cout << "already moved!\n";
} else {
std::cout << "argument: " << *std::move(move_me) << "\n";
move_me.reset();
}
}
int main() {
auto arg = std::make_unique<int>(42);
auto f = std::bind(foo, std::move(arg)); // this handler is now move-only
assert(!arg); // moved
{
boost::asio::io_context ctx;
post(
ctx,
std::move(f)); // move-only, so move the entire bind (including arg)
ctx.run();
}
f(); // already executed
}
Prints
argument: 42
already moved!
This is going to help a lot in code that uses a lot of composed operations: you can now bind the state of the operation into the handler with zero overhead, even if it's bigger and dynamically allocated.
Does anybody know why this program goes into an infinite loop, instead of stopping after 5s or so?
This happens with both the latest gcc and clang compiler; does atomic_bool suffer from hte same issues as a vector of bool?
If I use atomic<int> this works fine.
#include <algorithm>
#include <memory>
#include <utility>
#include <iostream>
#include <vector>
#include <functional>
#include <future>
#include <chrono>
using namespace std;
using namespace chrono_literals;
void send_heart_beat()
{
cout << "sending heartbeat" << endl;
}
std::future<void> f;
int main()
{
std::atomic<bool> stop(false);
f = std::async(std::launch::async,[&stop]() { while(!stop) { send_heart_beat(); std::this_thread::sleep_for(1s); } });
std::this_thread::sleep_for(5s);
stop = true;
}
std::atomic<bool> stop(false);
std::future<void> f;
These two variables are in different scopes, and f's scope is longer lived than stop's scope.
f = std::async(std::launch::async,[&stop]() { while(!stop) { send_heart_beat(); std::this_thread::sleep_for(1s); } });
here we bind a reference to stop into a lambda, and then store a (copy) of that lambda into an async object which is managed by f.
When f goes out of scope, its destructor waits for the async task to finish. But because f's scope is longer lasting than stop's, we leave the scope of stop before f waits for the thread to finish.
So our thread mindlessly continues accessing stop after stop no longer exists through a dangling reference.
This results in undefined behavior; any behavior by your program is acceptable to the standard.
I was just writing some small codes in c++11 and i came across a situation where i am not able to understand output.
For the below code constructor is called only once while destructor is called many times. if i replace delete[] p with delete p it behaves correctly but why delete[] p is giving this kind of output?
#include <iostream>
#include <memory>
class MyClass{
public:
MyClass(){std::cout<<"Constructor called..."<<std::endl;}
~MyClass(){std::cout<<"Destructor called..."<<std::endl;}
void printMe(){std::cout<<"PrintMe called..."<<std::endl;}
};
int main(){
std::shared_ptr<MyClass> ptr = std::shared_ptr<MyClass>(new MyClass(),
[](MyClass *p){std::cout<<"Custom Deleter ..for p"<<std::endl; delete[] p;});
}
Your program has undefined behavior.
You are allocating memory using new MyClass() and then deleting it with delete [] p.
Use just delete p;.
int main(){
std::shared_ptr<MyClass> ptr = std::shared_ptr<MyClass>(new MyClass(),
[](MyClass *p){std::cout<<"Custom Deleter ..for p"<<std::endl; delete p;});
}
It is not clear from the documentation. This template function returns void. The document mentions -
If the function cannot lock all objects, the function first unlocks
all objects it successfully locked (if any) before failing.
But how should the caller know it has failed ?
Does it block until it is successful and exception is the only failure scenario ?
It throws an error on any issue.
As a couple other SO members have mentioned to me in the past on my own questions, steer away from CPlusPlus.com - The Canonical Reference for Misinformation.
Please take this as an opportunity to learn the differences between c and c++. C requires return codes or side-effects to function arguments, while C++ offers exceptions in addition to the aforementioned.
Parameters
(none)
Return value
(none)
Exceptions
Throws std::system_error when errors occur, including errors from the
underlying operating system that would prevent lock from meeting its
specifications. The mutex is not locked in the case of any exception
being thrown.
Notes
lock() is usually not called directly: std::unique_lock and
std::lock_guard are used to manage exclusive locking.
Example
This example shows how lock and unlock can be used to protect shared
data.
#include <iostream>
#include <chrono>
#include <thread>
#include <mutex>
int g_num = 0; // protected by g_num_mutex
std::mutex g_num_mutex;
void slow_increment(int id)
{
for (int i = 0; i < 3; ++i) {
g_num_mutex.lock();
++g_num;
std::cout << id << " => " << g_num << '\n';
g_num_mutex.unlock();
std::this_thread::sleep_for(std::chrono::seconds(1));
}
}
int main()
{
std::thread t1(slow_increment, 0);
std::thread t2(slow_increment, 1);
t1.join();
t2.join();
}
I wrote accidentally a statement like
std::unique_ptr<Thing> m_thing;
m_thing->DoStuff();
instead of
std::unique_ptr<Thing> m_thing(new Thing);
m_thing->DoStuff();
the first example compiles and run, which doesn't make any sense to me because m_thing is not pointing to any object. Here a slightly bigger code example.
#include <iostream>
#include <memory>
class Thing
{
public:
~Thing(){ std::cout << "destructor of class Thing\n"; }
void DoStuff(){ std::cout << "doing stuff\n"; }
};
void Foo()
{
std::unique_ptr<Thing> m_thing;
m_thing->DoStuff(); //why does this work, since i suppose m_thing to be empty?
}
int main()
{
Foo();
std::cout << "after Foo()\n";
std::cin.get();
return 0;
}
Why can the "empty" m_thing unique_ptr invoke the DoStuff()-Method of the Thing-class?
i noticed also, that the destructor of Thing-class never gets invoked when declaring m_thing
with
std::unique_ptr<Thing> m_thing;
instead of
std::unique_ptr<Thing> m_thing(new Thing);
I didn't found any explanation of this behaviour via google, so i hope maybe someone can explain to me what is happening here behind the curtains.
Your program exhibits undefined behavior. "Seems to work" is one possible manifestation of undefined behavior. It's morally equivalent to
Thing* p = NULL;
p->DoStuff();
which I predict would also compile and run. DoStuff is called with NULL for this pointer - but it doesn't actually use this, that's why it doesn't crash and burn as you expect.
DoStuff isn't virtual and doesn't access any members of your object, so you can get away with calling it (I'm pretty sure this is unspecified behavior though). The default constructor for unique_ptr initializes it to nullptr, so it doesn't allocate any memory on its own.
Oh, and the destructor of course doesn't get called because unique_ptr doesn't invoke its deleter on nullptrs.