另一种使用std :: thread射腿的方法

C ++ 11标准在语言中引入了标准线程支持机制(它们通常称为流,但是这与术语流混为一谈,因此我将在俄语转录中使用原始的英语术语)。 但是,与C ++中的任何机制一样,该机制具有许多技巧,技巧和全新的射击方式。 最近,哈布雷(Habré)发表了一篇有关20种此类方法文章的翻译,但此列表并不详尽。 我想谈谈另一种与初始化std::thread构造函数中的std::thread实例有关的方法。


这是使用std::thread的简单示例:


 class Usage { public: Usage() : th_([this](){ run(); }) {} void run() { // Run in thread } private: std::thread th_; }; 

在这个最简单的示例中,代码看起来正确,但是有一个奇怪的问题:在调用构造函数std::thread Usage类std::thread实例尚未完全构建。 因此,可以为一个实例调用Usage::run() ,该实例的某些字段(在std::thread字段之后声明)尚未初始化,这又可能导致UB。 这在类代码适合屏幕的小示例中非常明显,但是在实际项目中,此陷阱可以隐藏在分支继承结构的后面。 让我们使示例复杂一些:


 class Usage { public: Usage() : th_([this](){ run(); }) {} virtual ~Usage() noexcept {} virtual void run() {} private: std::thread th_; }; class BadUsage : public Usage { public: BadUsage() : ptr_(new char[100]) {} ~BadUsage() { delete[] ptr_; } void run() { std::memcpy(ptr_, "Hello"); } private: char* ptr_; }; 

乍一看,该代码看起来也很正常,而且,它几乎总是可以按预期工作...直到星星累加,以便在初始化ptr_之前调用BadUsage::run() 。 为了证明这一点,在初始化之前添加一点延迟:


 class BadUsage : public Usage { public: BadUsage() : ptr_((std::this_thread::sleep_for(std::chrono::milliseconds(1)), new char[100])) {} ~BadUsage() { delete[] ptr_; } void run() { std::memcpy(ptr_, "Hello", 6); } private: char* ptr_; }; 

在这种情况下,调用BadUsage::run()导致分段错误 ,并且valgrind会抱怨访问未初始化的内存。


为了避免这种情况,有几种解决方案。 最简单的选择是使用两阶段初始化:


 class TwoPhaseUsage { public: TwoPhaseUsage() = default; ~TwoPhaseUsage() noexcept {} void start() { th_.reset(new std::thread([this](){ run(); })); } virtual void run() {} void join() { if (th_ && th_->joinable()) { th_->join(); } } private: std::unique_ptr<std::thread> th_; }; class GoodUsage : public TwoPhaseUsage { public: GoodUsage() : ptr_((std::this_thread::sleep_for(std::chrono::milliseconds(1)), new char[100])) {} ~GoodUsage() noexcept { delete[] ptr_; } void run() { std::memcpy(ptr_, "Hello", sizeof("Hello")); } private: char* ptr_; }; // ... GoodUsage gu; gu.start(); std::this_thread::sleep_for(std::chrono::milliseconds(100)); gu.join(); // ... 

Source: https://habr.com/ru/post/zh-CN444464/


All Articles