async使用注意事项

前言

一次,我封装了一个互斥锁,然后,打算写个程序测试一下。于是写了大概如下代码:

#include <memory>
#include <stdio.h>
#include <future>
#include <chrono>
#include <semaphore.h>
#include <exception>

class Mutex {
public:
    Mutex() {
        if (sem_init(&sem_, 0, 0) != 0)
            throw std::logic_error("sem_init");
    }
    ~Mutex() {
        sem_destroy(&sem_);
    }
    void lock() {
        if (sem_post(&sem_) != 0)
            throw std::logic_error("sem_post");
    }
    void unlock() {
        if (sem_wait(&sem_) != 0)
            throw std::logic_error("sem_post");
    }

private:
    Mutex(const Mutex&) = delete;
    Mutex(const Mutex&&) = delete;
    Mutex& operator=(const Mutex&) = delete;
    Mutex& operator=(const Mutex&&) = delete;

    sem_t sem_;
};

int main() {
    Mutex mtx;

    std::async([&mtx] {
                mtx.unlock();
            });
    std::async([&mtx] {
                mtx.lock();
            });
}

乍一看,应该没啥问题,可是,为啥卡死了,难道死锁了?

解决过程

把 async 换成 thread,可以正常运行。问题来了,async,这个被推荐使用的函数,它咋了
后来,我看到了这段话

若从 std::async 获得的 std::future 未被移动或绑定到引用,则在完整表达式结尾, std::future 的析构函数将阻塞直至异步计算完成,实质上令如下代码同步:
std::async(std::launch::async, []{ f(); }); // 临时量的析构函数等待 f()
std::async(std::launch::async, []{ g(); }); // f() 完成前不开始

对应上面的代码,也就是说,加锁那块会等待解锁的完成,才能继续执行下去,这就形成了死锁,如果改成这样就没问题了:

    auto a = std::async([&mtx] {
                mtx.unlock();
            });
    std::async([&mtx] {
                mtx.lock();
            });

结论

以调用 std::async 的方式获得的 std::future 的析构函数会阻塞程序的执行
同理的代码为:

void func() {
    auto a = std::async([]{
                std::this_thread::sleep_for(std::chrono::seconds(1));
            });
}

int main() {
    func();
    puts("hello");

    return 0;
}

猜你喜欢

转载自www.cnblogs.com/zuofaqi/p/12380792.html