I'd suggest to use fcntl http://man7.org/linux/man-pages/man2/fcntl.2.html which immediately returns an error value if a conflicting lock is attempted to be taken (see under Advisory record locking; F_SETLK). Then you can use a timer to implement retry with exponential back-off or similar. Alternately, I'd take "block all signals" with a grain of salt. You can use signals from the real-time signal range that isn't used by the system, and install a no-op signal handler. It will interrupt blocking operations (cause them to return with EINTR), but I strongly doubt that it'll affect non-blocking operations. (Signals are delivered on return from kernel space to user space and checking for them "too often" would be a performance penalty.) -- Stian ________________________________ From: Boost-users <boost-users-bounces@lists.boost.org> on behalf of Cristian Morales Vega via Boost-users <boost-users@lists.boost.org> Sent: Monday, November 19, 2018 6:04:01 PM To: boost-users@lists.boost.org Cc: Cristian Morales Vega Subject: [Boost-users] Making an ASIO asynchronous operation from flock() So I need to flock (http://man7.org/linux/man-pages/man2/flock.2.html) something (pre-existing flock in other piece of software to interoperate with) and I though: "I think I'm actually starting to understand ASIO, let's make a proper ASIO asynchronous operation with flock". Long story short, I now know better: I will never get ASIO. So my main issues are with the background thread. According to https://www.boost.org/doc/libs/develop/doc/html/boost_asio/overview/core/thr... "the threads ... must block all signals". OK, it makes sense, but... - I can make pthread_sigmask() the first thing once the std::thread starts executing. But, I can't really guarantee the thread will never receive a signal, can I? There is a small amount of time between the thread starting to be able to receive signals and pthread_sigmask() doing its job. Modifying the signal mask before the background thread is created (so also from the "not-background" thread) doesn't seem a lot better. - How do I cancel the asynchronous operation? flock() is blocking, not a lot I can do to unblock it. I could send a signal to the background thread, but... they must be blocked, so no. I can't join the thread while it's blocked in flock(). So... should it be detached? I could then maybe just destroy the std::thread, but I still need to call the handler with boost::asio::error::operation_aborted... So, my question: I'm making it more difficult than it is? There is some pattern I should be following which makes all this simple? See what I have below (sorry for the camel case) ------------------------------------------------------------------------------- #include <boost/asio.hpp> #include <boost/beast/core/bind_handler.hpp> #include <boost/system/error_code.hpp> #include <boost/system/system_error.hpp> #include <fcntl.h> #include <iostream> #include <sys/file.h> #include <sys/stat.h> #include <sys/types.h> #include <thread> namespace asio = boost::asio; using error_code = boost::system::error_code; using system_error = boost::system::system_error; class FLockablePosixDescriptor : public asio::posix::descriptor { public: enum class FlockType : int { SHARED = LOCK_SH, EXCLUSIVE = LOCK_EX }; using asio::posix::descriptor::descriptor; FLockablePosixDescriptor(FLockablePosixDescriptor &&) = default; FLockablePosixDescriptor &operator=(FLockablePosixDescriptor &&) = default; ~FLockablePosixDescriptor(); template <typename FLockToken> BOOST_ASIO_INITFN_RESULT_TYPE(FLockToken, void(error_code)) asyncFLock(FlockType type, FLockToken &&token); void cancel(); void cancel(error_code &ec); private: template <typename FLockHandler> void doFLock(int fd, FlockType type, FLockHandler &handler); asio::io_context mBackgroundContext{1}; std::thread mThread; }; FLockablePosixDescriptor::~FLockablePosixDescriptor() { mBackgroundContext.stop(); mThread.join(); } template <typename FLockToken> BOOST_ASIO_INITFN_RESULT_TYPE(FLockToken, void(error_code)) FLockablePosixDescriptor::asyncFLock(FlockType type, FLockToken &&token) { asio::async_completion<FLockToken, void(error_code)> init(token); mBackgroundContext.post([this, fd = native_handle(), type, handler = std::move(init.completion_handler), work = asio::make_work_guard(get_executor())] { doFLock(fd, type, handler); }); mThread = std::thread([this] { mBackgroundContext.run(); }); return init.result.get(); } template <typename FLockHandler> void FLockablePosixDescriptor::doFLock(int fd, FlockType type, FLockHandler &handler) { error_code ec; if (flock(fd, static_cast<int>(type)) == -1) { ec = error_code(errno, boost::system::system_category()); } asio::post(get_executor(), boost::beast::bind_handler(handler, ec)); } void FLockablePosixDescriptor::cancel() { error_code ec; cancel(ec); if (ec) { throw system_error(ec, "cancel"); } } void FLockablePosixDescriptor::cancel(error_code &ec) { // TODO: Cancel flock asio::posix::descriptor::cancel(ec); } int main() { boost::asio::io_context ioc; int fd = open("l", O_RDONLY); FLockablePosixDescriptor desc(ioc, fd); desc.asyncFLock(FLockablePosixDescriptor::FlockType::SHARED, [](const error_code &ec) { std::clog << "Done " << ec << std::endl; }); ioc.run(); } ------------------------------------------------------------------------------- _______________________________________________ Boost-users mailing list Boost-users@lists.boost.org https://lists.boost.org/mailman/listinfo.cgi/boost-users