zoukankan      html  css  js  c++  java
  • 管理线程之等待线程结束

    正常环境下等待线程结束

    假设须要等待线程结束。就在线程的实例对象上调用join()。

    管理线程之创建线程最后的样例中,用my_thread.join()取代my_thread.detach()就能够确保在函数终止前、局部变量析构前。线程会终止。在这样的情况下,用分开的线程来执行函数就没有什么意义了。

    由于在等待my_thread终止时,这个线程就不做不论什么事情了。在实际的project应用中,要么这个线程做自己的事。要么创建多个线程等待它们结束。

    join()是简单粗暴的,或者你等待线程终止。或者你不等待。

    假设想要更加精确控制,比如检查这个线程是否终止,或不过等待某一段时间。这是你必须使用其它方法比如条件变量等。线程调用join()会清理对应的内存空间。调用join()后,std::thread对象就不再和这个线程相关了。这也就是意味着。对于一个线程实例对象,你只能够调用join()一次,在调用后。这个线程对象就不在是joinable,调用joinable()会返回false。

    异常环境下的情况

    在线程对象销毁前,必须确保调用了join()或detach()。假设要分离一个线程,一般是在创建线程后马上调用detach(),因此这不是问题。

    可是假设要等待一个线程,那么必须小心去找到在代码的什么地方调用join()。也就是说。由于异常的发生,join()有可能被跳过而得不到运行。

    为了避免应用程序在异常时终止。要考虑到在异常情况下怎么做。

    通常来讲,在没有异常情况下假设调用join(),那么再异常情况下也须要调用join(),这样才干够避免意外的生命周期的问题。

    在实际代码中。能够使用try/catch:

    struct func;
    
    void f()
    {
    	int some_local_state=0;
    	func my_func(some_local_state);
    	std::thread t(my_func);
    	try
    	{
    		do_something_in_current_thread();
    	}
    	catch(...)
    	{
    		t.join();
    		throw;
    	}
    	t.join();
    }
    上面代码使用try/catch模块来确保调用join()。不管是否发生异常。

    使用try/catch有点冗长(verbose)。并且easy出现作用域错误,不是理想的解决方法。

    还有一种方法是RAII(Resource Acquisition Is Initialization资源获取即初始化),在类的析构函数中调用join()
    class thread_guard
    {
    	std::thread& t;
    public:
    	explicit thread_guard(std::thread& t_):t(t_){}
    	~thread_guard()
    	{
    		if(t.joinable())//先检查是否已经掉用过join
    			t.join();
    	}
    	//以下是禁止使用拷贝构造函数和赋值操作符。这须要
    	//C++11的支持
    	thread_guard(thread_guard const&)=delete;
    	thread_guard& operator=(thread_guard const&)=delete;
    };
    struct func;
    void f()
    {	
    	int some_local_state=0;
    	func my_func(some_local_state);
    	std::thread t(myfunc);
    	thread_guard g(t);
    	do_something_in_current_thread();
    }
    上面的原理是局部变量会依照构造的逆顺序销毁,由于这些变量都在栈上。thread_guard对象g首先销毁。在它的析构函数调用了join()。

    上面代码中禁用了复制构造函数和赋值操作符。

    这是为了防止thread_guard对象超出thread对象的生命周期。

    假设不须要等待线程终止。那么能够用分离来避免异常安全问题。

    在后台执行线程

    在线程对象调用detach()后,线程就分离了,在后台执行了,没有直接的方法了和它通信了。线程在后台执行后,控制权就交给了C++ Runtime Library,来保证当线程存在时资源的回收使用。

    分离的线程叫做守护线程。这个来源于Unix中的守护进程(在后台执行,没有显示的用户接口)。这种线程经常是长时间执行的。它们经常在应用的整个生命周期都在执行,清理不使用的对象或者优化数据结构等。

    还有一种极端情况是,它能够使用分离的线程(假设有一种机制能够检測某个线程是否完毕任务,或线程是用来即发即弃任务“fire and forget”)。

    在分离一个线程前,必须确保线程能够分离。即std:thread的对象还和线程关联。和调用join()前的检查同样,先调用joinable(),假设返回true,再调用detach。

    考虑一个文件处理的应用。

    这个应用能够同一时候编辑多个文档。编辑窗体是独立的,它们的代码同样,可是处理的数据不同。一种处理的方法就是在打开一个新的文档时就创建新的线程,然后分离。

    void edit_document(std::string const& filename)
    {
    	open_document_and_display_gui(filename);
    	while(!done_editing())//编辑是否完毕
    	{
    		user_command cmd=get_user_input();//用户输入命令
    		if(cmd.type==open_new_document)//要打开新文档
    		{
    			std::string const new_name=get_filename_from_user();
    			std::thread t(edit_document,new_name);//创建线程
    			t.detach();//分离,在后台执行
    		}
    		else
    		{
    			process_user_input(cmd);
    		}
    	}
    }

  • 相关阅读:
    自建mail服务器之一:dns解析
    区间树
    3d tech
    3d
    平板比较
    Node。js 访问gmail
    node nightmare 网页自动化测试 sample
    node start
    中國駐香港外交部
    create a simple COM object
  • 原文地址:https://www.cnblogs.com/yfceshi/p/6945694.html
Copyright © 2011-2022 走看看