facebook/folly

use ParkingLot to construct WaitableMutex will crash

EdagrHW opened this issue · 0 comments

class WaitableMutex : public std::mutex {
    using Lot = ParkingLot<std::function<bool(void)>>;
    static Lot lot;

   public:
    void unlock() {
        bool unparked = false;
        lot.unpark(uint64_t(this), [&](std::function<bool(void)> wfunc) {
            if (wfunc()) {
                unparked = true;
                return UnparkControl::RemoveBreak;
            } else {
                return UnparkControl::RemoveContinue;
            }
        });

        if (!unparked) {
            std::mutex::unlock();
        }
    }

    template <typename Wait>
    void wait(Wait wfunc) {
        lot.park(
            uint64_t(this), wfunc, [&]() { return !wfunc(); }, [&]() { std::mutex::unlock(); });
    }
};

WaitableMutex::Lot WaitableMutex::lot;

int main() {
    // test();
    std::atomic<bool> go{false};
    WaitableMutex mu;
     std::thread t([&]() {
         std::unique_lock<WaitableMutex> g(mu);
         mu.wait([&]() { return go == true; });
     });
    std::this_thread::sleep_for(std::chrono::seconds(1));

    {
        std::lock_guard<WaitableMutex> g(mu);
        go = true;
    }
    t.join();
}
/*
error: unlock of unowned mutex
reason:
"When destructed twice, the unlock method will be called twice. The first time it will not execute std::mutex::unlock(), but the second time it will. And during the wait operation, std::mutex::unlock() has already been called once."
*/