3 ms·
You only achieved a deadlock by re-introducing mutexes.
by mgaunard 11mo ago
You only achieved a deadlock by re-introducing mutexes.
- gpderetta 11mo agoGiven: Something someting; async_mutex mtx; void my_critical_section(Data&); 1: await mtx.lock(); my_critical_section(something); await mtx.unlock(); 2: auto my_locked_critical_section() { await mtx.lock(); my_critical_section(something); await mtx.unlock(); } ... await my_locked_critical_section(something); 3: auto locked(auto mtx, auto critical_section) { await mtx.lock(); critical_section(); await mtx.unlock(); } ... await locked(mtx, [&]{ my_critical_section(something); }); 4: template<class T> struct synchronized { async_mutex mtx; T data; auto async_visit(auto fn) { locked(mtx, [fn,&data]{ fn(data); }); } }; synchronized<Something> something; await something.async_visit([](Something& data) { my_critical_section(something); }); If 1 is a mutex, at which point it stops being a mutex? Note that 4 is my initial example.
- mgaunard 11mo agoit's a mutex iff it's acquiring a resource exclusively. which you don't need to do for synchronization of coroutines since you can control in which order things are scheduled and whether that's done concurrently or not.
- gpderetta 11mo agoNot if you have multiple schedulers. Case in point: asio.strand or execution::on [1]. And even with one scheduler it makes sense to explicitly mark your critical sections. Really, at the end of the day the primary purpose of a mutex is serialization of all operations on some data. The blocking behaviour is just a way to implement it. [1] https://en.cppreference.com/w/cpp/execution/on.html https://en.cppreference.com/w/cpp/execution/on.html
- mgaunard 11mo agoMutexes are a problematic pattern that doesn't compose, see the article.