【发布时间】:2012-12-15 14:28:40
【问题描述】:
【问题讨论】:
标签: c++ multithreading c++11 std stdthread
【问题讨论】:
标签: c++ multithreading c++11 std stdthread
@bamboon 的回答很好,但我觉得这值得更强有力的声明。
无论您使用哪种语言,您的程序都会获取和释放资源:内存、文件描述符……对于一次性触发的简单程序,泄漏资源无关紧要:当程序结束时,现代操作系统会自动占用资源返回;但是对于长时间运行的程序,基本要求是不泄漏资源,或者至少不重复。
因此,您应该从一开始就被教导,当您获得资源时,您必须确保它在某一时刻被释放:
void foo(int i) {
int* array = malloc(sizeof(int) * i);
/* do something */
free(array);
}
所以,问自己这个问题:
嗯,正如我们所说,当程序结束时,操作系统会收集资源,因此假设(这是一些假设)您没有在 另一个 系统上获取资源或该系统受到很好的保护,免受此类虐待,没有伤害,没有犯规。
但是,当你杀死一个线程时,程序仍然运行,因此操作系统不会收集资源。您泄漏了内存,您锁定了一个无法再解锁的写入文件,... 您不应杀死线程。
高级语言有办法处理这个问题:异常。因为程序无论如何都应该是异常安全的,Java(例如)将通过暂停线程来终止线程,在执行点抛出异常,然后轻轻展开堆栈。然而,C++ 中还没有这样的工具。
不可能吗?不,显然不是。实际上,您可以完美地重用相同的想法:
std::thread,interruptible_thread 类也将包含一个中断标志std::thread,并以线程本地方式存储即:
// Synopsis
class interrupt_thread_exception;
class interruptible_thread;
void check_for_interrupt();
// Interrupt exception
class interrupt_thread_exception: public virtual std::exception {
public:
virtual char const* what() const override { return "interrupt"; }
}; // class interrupt_thread_exception
// Interruptible thread
class interruptible_thread {
public:
friend void check_for_interrupt();
template <typename Function, typename... Args>
interruptible_thread(Function&& fun, Args&&... args):
_thread([](std::atomic_bool& f, Function&& fun, Args&&... args) {
_flag_ref = &f; fun(std::forward<Args>(args)...);
},
_flag,
std::forward<Function>(fun),
std::forward<Args>(args)...)
{}
bool stopping() const { return _flag.load(); }
void stop() { _flag.store(true); }
private:
static thread_local std::atomic_bool* _flag_ref = nullptr;
std::atomic_bool _flag = false;
std::thread _thread;
}; // class interruptible_thread
// Interruption checker
inline void check_for_interrupt() noexcept(false) {
if (not interruptible_thread::_flag_ref) { return; }
if (not interruptible_thread::_flag_ref->load()) { return; }
throw interrupt_thread_exception();
} // check_for_interrupt
现在您可以在线程代码中添加适当的中断检查。
【讨论】:
void foo(int) 已经不是异常安全的了,如果你在 `/* do something */' 中间有一个中断检查,它仍然是错误的。
try/catch 块、RAII 等......而残酷的中断让你没有清理工具。注意我说的是检查中断在适当的地方。!而且你仍然可以中断 foo,只要你捕捉到异常以便执行 free ......但这并不是真正的意思,我更多地展示了清理的需要明确而一个构建良好的 C++ 程序显然会使用 RAII。
terminate() 功能使用了大致相似的方法。他们的术语:“中断点”。 boost::thread 相对于上述代码的一个优势: boost::thread 还具有对休眠操作中断的内置支持。例如。 boost::thread::sleep_for().
getline。并且没有标准的非阻塞方式来做到这一点。
你不能。
std::threads 不可中断。您可以使用提供此功能的boost::thread。
Boost 通过定义“中断点”来实现这一点,如果线程被中断并到达这样的点,线程将在该点结束。
尽管如此,大多数时候考虑重新设计可能是实现您想要实现的目标的最简洁、最简单的方法。
如果您仍在寻找可中断线程的 C++11 实现,请查看 Anthony Williams(boost 线程的所有者)一书“C++ Concurrency in Action”。他介绍了如何实现这一目标的基本实现。
std::thread::native_handle 使您可以访问平台特定的底层线程句柄,该句柄可能支持中断,但是这种方法使您的代码不可移植并且可能以任何方式都不干净。
【讨论】: