mercredi 31 mai 2017

condition variable and #pragma pack bug

I found out that this piece of code doesn't work as intended:

#pragma pack(push, 1)

class myclass {
protected:
    bool mycrasher[1];
    std::mutex mtx;
    std::condition_variable cv;

    void thread_func() {
        std::this_thread::sleep_for(std::chrono::seconds(1));

        std::chrono::milliseconds timeout(1000);
        std::unique_lock<std::mutex> l(mtx, std::defer_lock);
        while (true) {
            auto now = std::chrono::system_clock::now();
            l.lock();
            while (true) {
                std::cout << "Waiting..." << std::endl;
                auto result = cv.wait_until(l, now + timeout);
                std::cout << "Timed out..." << std::endl;
                if (result == std::cv_status::timeout)
                    break;
            }
            l.unlock();
        }
    }   

public:
    myclass() { 
        std::lock_guard<std::mutex> l(mtx);
        std::thread *t = new std::thread(&myclass::thread_func, this);
        t->detach();
    };

    void start() {
        std::cout << "myclass started." << std::endl;
        std::cout << "sizeof(std::mutex) = " << sizeof(std::mutex) << std::endl;
        std::cout << "sizeof(std::condition_variable) = " << sizeof(std::condition_variable) << std::endl;
    }
};
#pragma pack(pop)

int main() {
    myclass x;
    x.start();
    std::this_thread::sleep_for(std::chrono::seconds(60));
}

I expected the code to wait for one second on the cv.wait_until call and then repeat, but is simply hangs on the call. The issue (intuitively) goes away if I remove the #pragma directives, because I'm packing the mutex and the CV. However, when I run this code I get:

myclass started.
sizeof(std::mutex) = 40
sizeof(std::condition_variable) = 48

with or without the pragma, so it seems the packing is not the real problem.

In addition, I discovered that if I align the mycrasher variable to a 4-bytes boundary the problem disappears as well. Likewise, if I move the variable after the std::condition_variable cv declaration the problem disappears, but when moved between std::mutex mtx and std::condition_variable cv it still persists.

Why the snippet hangs on the cv.wait_until call when the CV is not properly aligned? A performance hit would be expected, but not a plain stall.

Aucun commentaire:

Enregistrer un commentaire