I'm having problems using named_mutex, which I am trying to use to determine if another instance of my application is running.
I defined a global variable:
named_mutex dssMutex{ open_or_create, "DeepSkyStacker.Mutex.UniqueID.12354687" };
In main() I then wrote:
if (!dssMutex.try_lock()) firstInstance = false;
and at the end of main() after all the catch stuff I did:
dssMutex.unlock();
The problem I have encountered is that try_lock() is returning false when this is the only instance of my program in the system (just after a reboot). I also see this in the debug log (which may just be an artefact of try_lock()):
Exception thrown at 0x00007FFB838C4FD9 in DeepSkyStacker.exe: Microsoft C++ exception: boost::interprocess::interprocess_exception at memory location 0x00007FF5FFF7EF00.
So what am I doing wrong?
Thanks
David
Three things:
you should not unlock if try_lock returned false;
you should be exception safe, which is easier with the scoped_lock helper
Boost's interprocess locking primitives are not robust mutexes. This means that if your process gets hard-terminated without unlocking, the lock will be stuck. To the best of my knowledge the implementation(s) on Windows contain a "boot time" field which serves to recover the lock after a reboot, though, so your described scenario should really not be a problem.
The Exception
The exception shown should not be a problem unless it goes unhandled. If you're using Visual Studio you can configure the debugger to break on exceptions thrown or unhandled. The best explanation for the message is that it is handled internally. The worst explanation is that you're not handling it. In that case it will explain that the lock is not released.
Note that the exception might be cause by trying to unlock after failing to try_lock?
Code Sample
Here's how I'd use a deffered scope-lock to achieve exception safety:
#include <boost/interprocess/sync/named_mutex.hpp>
#include <boost/interprocess/sync/scoped_lock.hpp>
#include <iostream>
#include <thread>
namespace bip = boost::interprocess;
using namespace std::chrono_literals;
int main(int, char** argv) {
bip::named_mutex dssMutex{bip::open_or_create, "UniqueID.12354687"};
bip::scoped_lock<bip::named_mutex> lk(dssMutex, bip::defer_lock);
bool const firstInstance = lk.try_lock();
std::cout << argv[0] << (firstInstance?" FRIST!":" SECOND") << std::flush;
std::this_thread::sleep_for(1s);
std::cout << " Bye\n" << std::flush;
}
Coliru cannot handle it but here's what that does locally:
Signal Handling
Now, as mentioned, this is still not robust, but you can make it less bad by at least handling e.g. SIGINT (what happens on POSIX when you Ctrl-C in the terminal):
#include <boost/asio.hpp>
#include <boost/interprocess/sync/named_mutex.hpp>
#include <boost/interprocess/sync/scoped_lock.hpp>
#include <iostream>
#include <thread>
namespace bip = boost::interprocess;
using namespace std::chrono_literals;
int main(int, char** argv) {
boost::asio::thread_pool ioc(1);
boost::asio::signal_set ss(ioc, SIGINT, SIGTERM);
ss.async_wait([](auto ec, int s) {
if (ec == boost::asio::error::operation_aborted)
return;
std::cerr << "signal " << s << " (" << ec.message() << ")" << std::endl;
});
bip::named_mutex dssMutex{bip::open_or_create, "UniqueID.12354687"};
bip::scoped_lock<bip::named_mutex> lk(dssMutex, bip::defer_lock);
bool const firstInstance = lk.try_lock();
std::cout << argv[0] << (firstInstance?" FRIST!":" SECOND") << std::flush;
std::this_thread::sleep_for(1s);
std::cout << " Bye\n" << std::flush;
ss.cancel();
ioc.join();
}
Now it's okay to interrupt the processes:
for a in {1..10}; do sleep "0.$RANDOM"; ./one; done&
for a in {1..10}; do sleep "0.$RANDOM"; ./two; done&
sleep 3; pkill -INT -f ./one;
sleep 5; pkill -INT -f ./two
If you look closely, the handler doesn't actually do anything now. So likely you want to make sure it cleanly shuts down main.
Related
I'm dabbling in coroutines in respect to boost::asio, and I'm confused by exception handling. Judging by the examples in the docs, it looks like any 'fail' error_code is turned into an exception - so I hopefully assumed that any exception thrown would also be propagated back to the co_spawn call. But that doesn't appear to be case:
#define BOOST_ASIO_HAS_CO_AWAIT
#define BOOST_ASIO_HAS_STD_COROUTINE
#include <iostream>
#include <boost/asio/awaitable.hpp>
#include <boost/asio/co_spawn.hpp>
#include <boost/asio/detached.hpp>
#include <boost/asio/io_context.hpp>
#include <boost/asio/executor_work_guard.hpp>
namespace this_coro = boost::asio::this_coro;
boost::asio::awaitable<void> async_op()
{
std::cout << "About to throw" << std::endl;
throw std::runtime_error{"Bang!"};
}
int main()
{
auto ctx = boost::asio::io_context{};
auto guard = boost::asio::make_work_guard(ctx.get_executor());
boost::asio::co_spawn(ctx, async_op, boost::asio::detached);
ctx.run();
}
If this is ran in a debugger, you can see the exception being thrown, but then it just seems to hang. Pausing the debugger shows that the ctx.run() is waiting for new work (due to the executor_work_guard). So it looks like something inside boost::asio has silently swallowed the exception.
As an experiment, I switched the async operation to use boost::asio library calls:
boost::asio::awaitable<void> async_op()
{
auto executor = co_await this_coro::executor;
auto socket = boost::asio::ip::tcp::socket{executor};
std::cout << "Starting resolve" << std::endl;
auto resolver = boost::asio::ip::tcp::resolver{executor};
const auto endpoints = co_await resolver.async_resolve("localhost",
"4444",
boost::asio::use_awaitable);
std::cout << "Starting connect (num endpoints: " << endpoints.size() << ")" << std::endl;
co_await boost::asio::async_connect(socket, endpoints, boost::asio::use_awaitable);
std::cout << "Exited" << std::endl;
}
I don't have a server running on port 4444, so this should fail immediately - and it does but silently. Pausing the debugger shows that it's stuck in epoll waiting for something (I'm on Linux).
Swapping the async_connect CompletionToken to a boost::asio::redirect_error shows that the operation is failing:
co_await boost::asio::async_connect(socket,
endpoints,
boost::asio::redirect_error(boost::asio::use_awaitable, ec));
std::cout << "Exited: " << ec.message() << std::endl;
Yields:
Starting resolve
Starting connect (num endpoints: 1)
Exited: Connection refused
So how do I propagate exceptions, and create them from error_codes, out of coroutines in boost::asio?
boost::asio::co_spawn creates a separate thread. This means that exceptions are not propagated. You can read more about this here:
Will main() catch exceptions thrown from threads?
How can I propagate exceptions between threads?
But co_spawn supports a completion handler with the signature void(std::exception_ptr, R). In your example you used boost::asio::detached which means the completion result is ignored. To propagate it simply write a custom handler.
For some time I have been trying to use std::thread, and in my project i wanted to make sure that the threads are not making one thing couple times at once, that's why i am trying to make a simple project that has something like "check" if thread is done, and then start again
#include <future>
#include <thread>
#include <chrono>
#include <iostream>
using namespace std::chrono_literals;
void Thing()
{
std::this_thread::sleep_for(3s);
}
int main()
{
std::packaged_task<void()> task(Thing);
auto future = task.get_future();
std::thread t(std::move(task));
while (true) {
auto status = future.wait_for(0ms);
if (status != std::future_status::ready)
{
std::cout << "not yet" << std::endl;
}
else
{
t.join();
std::cout << "Join()" << std::endl;
}
std::this_thread::sleep_for(300ms);
}
}
using this code i have error at line with std::cout << "Join()" << std::endl; and the error says: Unhandled exception at 0x7632A842 in dasd.exe: Microsoft C++ exception: std::system_error at memory location 0x00AFF8D4.
this error is comes out when the thread is ready, and t.join() is called.
output of this project:
not yet
...
not yet
Join()
Thank You in advance
As you can see https://en.cppreference.com/w/cpp/thread/thread/join
join has as post condition
joinable() is false
and in error condition
invalid_argument if joinable() is false
So you cannot call it twice as you do.
You probably want to break the loop once you call join or rewrite your loop such as:
while (future.wait_for(300ms) != std::future_status::ready) {
std::cout << "not yet" << std::endl;
}
t.join();
std::cout << "Join()" << std::endl;
Actually, you don't need a while loop there. Instead, you could simply call join.
What join does is to wait for the thread to finish its job. After the thread finishes its job, it exits and cleans the stack and the second call to join doesn't make sense at all.
I also would suggest using std::async in case you want an async function that also returns a value.
In the following example I try to write some data to a child process, which processes the data and writes it to a file. After closing the stream the parent process waits indefinitely for the child to finish. I am at a loss to know how to indicate that I’m done writing the data and would like the child process to stop reading and finish whatever it is doing. According to the documentation calling terminate would send a SIGKILL which I don’t think is what I want.
What am I missing? I checked this question but I would rather try to make the actual code work with synchronous IO first.
#include <boost/process.hpp>
#include <iostream>
namespace bp = boost::process;
int main(int argc, char **argv)
{
boost::process::opstream in{};
boost::process::child child("/path/to/test.py", bp::std_in < in);
in << "test1\n";
in << "test2\n";
in << "test3\n";
in << std::flush;
std::cerr << "Closing the stream…\n";
in.close();
std::cerr << "Waiting for the child to exit…\n";
child.wait(); // Parent seems to hang here.
return 0;
}
test.py just writes the data to a file like so:
#!/usr/local/homebrew/opt/python#3.8/bin/python3
import sys
with open("/tmp/test.txt", "w") as f:
for line in sys.stdin:
f.write(line)
After inspecting the source code, I found out that closing the stream did not close the associated pipe at least in this case. Doing that manually did solve the issue:
...
in.close();
in.pipe().close();
child.wait(); // Does not hang.
The documentation warns that using synchronous IO to child processes is prone to deadlock.
Here's a minimal reword to async IO:
#include <boost/process.hpp>
#include <iostream>
namespace bp = boost::process;
int main() {
boost::asio::io_context ioc;
bp::async_pipe in{ioc};
bp::child child("./test.py", bp::std_in < in, bp::std_out.close());
for (auto msg : { "test1\n", "test2\n", "test3\n" }) {
write(in, bp::buffer(msg, strlen(msg)));
}
std::cerr << "Closing the pipe…\n";
in.close();
std::cerr << "Waiting for the child to exit…\n";
ioc.run(); // already awaits completion
child.wait(); // Parent seems to hang here.
}
You can make it more realistic by doing some delays:
#include <boost/process.hpp>
#include <iostream>
using namespace std::chrono_literals;
namespace bp = boost::process;
int main() {
boost::asio::io_context ioc;
bp::async_pipe in{ioc};
bp::child child("./test.py", bp::std_in < in, bp::std_out.close());
std::thread th([&] {
for (auto msg : { "test1\n", "test2\n", "test3\n" }) {
write(in, bp::buffer(msg, strlen(msg)));
std::this_thread::sleep_for(1s);
}
std::cerr << "Closing the pipe…\n";
in.close();
});
std::cerr << "Waiting for the child to exit…\n";
ioc.run(); // already awaits completion
th.join();
child.wait(); // Parent seems to hang here.
}
For fullblown async IO see other examples:
simultaneous read and write to child's stdio using boost.process
How to retrieve program output as soon as it printed?
Running a process using boost process in async mode with timeout
I'm trying to switch an application over from using boost::interprocess::named_mutex to boost::interprocess::file_lock for interprocess synchronization, but when I did so I noticed that my condition variables were never being woken up.
I've created two examples that demonstrate the types of changes I made and the issues I'm seeing. In both examples the same application should periodically send notifications if invoked with any arguments, or wait for notifications if invoked with no arguments
Originally my application used name_mutex and named_condition. The below example using name_mutex and named_condition works as expected: every time the "sender" application prints out "Notifying" the "receiver" application prints out "Notified!" (provided I manually clean out /dev/shm/ between runs).
#include <iostream>
#include <boost/interprocess/sync/scoped_lock.hpp>
#include <boost/interprocess/sync/named_condition.hpp>
#include <boost/interprocess/sync/named_mutex.hpp>
#include <boost/thread.hpp>
int main(int argc, char** argv)
{
boost::interprocess::named_mutex mutex(boost::interprocess::open_or_create,
"mutex");
// Create condition variable
boost::interprocess::named_condition cond(boost::interprocess::open_or_create, "cond");
while(true)
{
if(argc > 1)
{// Sender
std::cout << "Notifying" << std::endl;
cond.notify_all();
boost::this_thread::sleep_for(boost::chrono::seconds(1));
}
else
{// Receiver
std::cout << "Acquiring lock..." << std::endl;
boost::interprocess::scoped_lock<boost::interprocess::named_mutex> lock(mutex);
std::cout << "Locked. Waiting for notification..." << std::endl;
cond.wait(lock);
std::cout << "Notified!" << std::endl;
}
}
return 0;
}
The following code represents my attempt to change the working code above from using name_mutex and named_condition to using file_lock and named_condition_any
#include <iostream>
#include <boost/interprocess/sync/scoped_lock.hpp>
#include <boost/interprocess/sync/named_condition_any.hpp>
#include <boost/interprocess/sync/file_lock.hpp>
#include <boost/thread.hpp>
int main(int argc, char** argv)
{
// Second option for locking
boost::interprocess::file_lock flock("/tmp/flock");
// Create condition variable
boost::interprocess::named_condition_any cond(boost::interprocess::open_or_create,
"cond_any");
while(true)
{
if(argc > 1)
{// Sender
std::cout << "Notifying" << std::endl;
cond.notify_all();
boost::this_thread::sleep_for(boost::chrono::seconds(1));
}
else
{// Receiver
std::cout << "Acquiring lock..." << std::endl;
boost::interprocess::scoped_lock<boost::interprocess::file_lock> lock(flock);
std::cout << "Locked. Waiting for notification..." << std::endl;
cond.wait(lock);
std::cout << "Notified!" << std::endl;
}
}
return 0;
}
However I can't seem to get the "receiver" application to wake up when notified. The "sender" happily prints "Notifying" at ~1Hz, but the "receiver" hangs after printing "Locked. Waiting for notification..." once.
What am I doing wrong with my file_lock/named_condition_any implementation?
This appears to be caused by a bug in the implementation of boost::interprocess::named_condition_any.
boost::interprocess::named_condition_any is implemented using an instance of boost::interprocess::ipcdetail::shm_named_condition_any. boost::interprocess::ipcdetail::shm_named_condition_any has all of the member variables associated with its implementation aggregated into a class called internal_condition_members. When shm_named_condition_any is constructed it either creates or opens shared memory. If it creates the shared memory it also instantiates an internal_condition_members object in that shared memory.
The problem is that shm_named_condition_any also maintains a "local" (i.e. just on the stack, not in shared memory) member instance of an internal_condition_members object, and its wait, timed_wait, notify_one, and notify_all functions are all implemented using the local internal_condition_members member instead of the internal_condition_members from shared memory.
I was able to get the expected behavior from my example by editing boost/interprocess/sync/shm/named_condition_any.hpp and changing the implementation of the shm_named_condition_any class as follows:
typedef ipcdetail::condition_any_wrapper<internal_condition_members> internal_condition;
internal_condition m_cond;
to
typedef ipcdetail::condition_any_wrapper<internal_condition_members> internal_condition;
internal_condition &internal_cond()
{ return *static_cast<internal_condition*>(m_shmem.get_user_address()); }
and changing all usages of m_cond to this->internal_cond(). This is analogous to how the shm_named_condition class is implemented.
I am converting a previous thread wrapper around pthreads to std::thread.
However c++11 does not have any way to cancel the thread. I REQUIRE, nonetheless, to cancel threads since they may be performing a very lengthy task inside an external library.
I was considering using the native_handle that gives me pthread_id in my platform. I'm using gcc 4.7 in Linux (Ubuntu 12.10). The idea would be:
#include <iostream>
#include <thread>
#include <chrono>
using namespace std;
int main(int argc, char **argv) {
cout << "Hello, world!" << endl;
auto lambda = []() {
cout << "ID: "<<pthread_self() <<endl;
while (true) {
cout << "Hello" << endl;
this_thread::sleep_for(chrono::seconds(2));
}
};
pthread_t id;
{
std::thread th(lambda);
this_thread::sleep_for(chrono::seconds(1));
id = th.native_handle();
cout << id << endl;
th.detach();
}
cout << "cancelling ID: "<< id << endl;
pthread_cancel(id);
cout << "cancelled: "<< id << endl;
return 0;
}
The thread is canceled by an exception thrown by pthreads.
My question is:
Will there be any problem with this approach (besides not being portable)?
No, I don't think that you will not have additional problems than:
not being portable
having to program _very_very_ carefully that all objects of the cancelled thread are destroyed...
For example, the Standard says that when a thread ends variables will be destroyed. If you cancel a thread this will be much harder for the compiler, if not impossible.
I would, therefore recommend not to cancel a thread if you can somehow avoid it. Write a standard polling-loop, use a condition variable, listen on a signal to interrupt reads and so on -- and end the thread regularly.