std::mutex with RAII but finish & release in background thread std::mutex with RAII but finish & release in background thread multithreading multithreading

std::mutex with RAII but finish & release in background thread


Updated Answer:@Revolver_Ocelot is right that my answer encourages undefined behavior, which I'd like to avoid.

So let me use the simple Semaphore implementation from this SO Answer

#include <mutex>#include <thread>#include <condition_variable>class Semaphore {public:    Semaphore (int count_ = 0)        : count(count_) {}    inline void notify()    {        std::unique_lock<std::mutex> lock(mtx);        count++;        cv.notify_one();    }    inline void wait()    {        std::unique_lock<std::mutex> lock(mtx);        while(count == 0){            cv.wait(lock);        }        count--;    }private:    std::mutex mtx;    std::condition_variable cv;    int count;};class SemGuard{    Semaphore* sem;public:    SemGuard(Semaphore& semaphore) : sem(&semaphore)    {        sem->wait();    }    ~SemGuard()    {        if (sem)sem->notify();    }    SemGuard(const SemGuard& other) = delete;    SemGuard& operator=(const SemGuard& other) = delete;    SemGuard(SemGuard&& other) : sem(other.sem)    {        other.sem = nullptr;    }    SemGuard& operator=(SemGuard&& other)    {        if (sem)sem->notify();        sem = other.sem;        other.sem = nullptr;        return *this;    }};class CamIface{   Semaphore sem;   CameraHw camera;public:   CamIface() : sem(1){}   Image acquire(){      SemGuard guard(sem);      camera.StartCapture();      Image img=camera.GetNextFrame();      std::thread bg([&](SemGuard guard){         camera.StopCapture(); // takes a long time       }, std::move(guard));       bg.detach();       return img;   };};

Old Answer:Just like PanicSheep said, move the mutex into the thread. For example like this:

std::mutex mut;void func(){    std::unique_lock<std::mutex> lock(mut);    std::thread bg([&](std::unique_lock<std::mutex> lock)    {         camera.StopCapture(); // takes a long time    },std::move(lock));    bg.detach();}

Also, just to remark, don't do this:

std::thread bg([&](){     std::unique_lock<std::mutex> local_lock = std::move(lock);     camera.StopCapture(); // takes a long time     local_lock.release(); // release the lock here, somehow});

Because you're racing the thread startup and the function scope ending.


Move the std::unique_lock to the background thread.


You can use both mutex and condition_variable to do the synchronization. Also it's dangerous to detach the background thread, since the thread might still running while the CamIface object has been destructed.

class CamIface {public:    CamIface() {        background_thread = std::thread(&CamIface::stop, this);    }    ~CamIface() {        if (background_thread.joinable()) {            exit = true;            cv.notify_all();            background_thread.join();        }    }    Image acquire() {        std::unique_lock<std::mutex> lock(mtx);        cv.wait(lock, [this]() { return !this->stopping; });        // acquire your image here...        stopping = true;        cv.notify_all();        return img;    }private:    void stop() {        while (true) {            std::unique_lock<std::mutex> lock(mtx);            cv.wait(lock, [this]() { return this->stopping || this->exit; });            if (exit) return;   // exit if needed.            camera.StopCapture();            stopping = false;            cv.notify_one();        }    }    std::mutex mtx;    std::condition_variable cv;    atomic<bool> stopping = {false};    atomic<bool> exit = {false};    CameraHw camera;    std::thread background_thread;};