C++多线程(一)——线程管理

多线程是……/*此处省略一万字,省略的文字详细说明了什么是多线程、其历史及其发展、使用多线程的好处和缺点以及C/C++对多线程的支持的历史*/
C++标准库自C++11标准以来开始支持多线程,多线程相关的类在thread头文件中,所以使用请先必须#include <thread>

启动一个线程

启动一个线程非常简单,例程如下:
#include <iostream>
#include <thread>

void test1()
{
	std::cout << "------This message from another thread.-------" << std::endl;
}

int main()
{
	std::thread t(test1);
	std::cout << "-------This message from main thread.-------" << std::endl;
	t.join();
	std::cin.get();
	return 0;
}
上面的代码std::thread t(test1)创建并且启动一个线程,所启动的线程将执行test1()函数中的代码。
线程必须要有一个可调用对象来初始化和启动,这个可调用对象可以是函数对象、一般函数、lambda表达式或者成员函数或者由std::bind()产生的可调用对象。
下面是启动线程的几种不同方式的例程:
#include <iostream>
#include <thread>

//一般函数
void test1()
{
	std::cout << "------This message from another thread.-------" << std::endl;
}

void test2(int c)
{
	std::cout << "parameter is " << c << std::endl;
}

class callable
{
public:
	void operator()()
	{
		std::cout << "message from callable object" << std::endl;
	}
	void mem()
	{
		std::cout << "message from member func." << std::endl;
	}
};

int main()
{
	//common function
	std::thread t1(test1);
	//bind
	std::thread t2(std::bind(test2, 10057));

	callable obj;
	//callabel object
	std::thread t3(obj);
	//member function
	std::thread t4(&callable::mem, &obj);
	//lambda function.
	std::thread t5([]() {/*nothing to do.*/});
	std::cout << "-------This message from main thread.-------" << std::endl;
	t1.join();
	t2.join();
	t3.join();
	t4.join();
	t5.join();
	std::cin.get();
	return 0;
}

参数传递

传递进线程中运行的函数也可以有参数,传递参数到线程中也不是什么难题,代码如下:
void f(int i,std::string const& s);
std::thread t(f,3,”hello”);
但需要注意的是,所有传递进线程的参数,线程首先将实参值复制到其当前线程空间中。然后使用的是线程空间中的变量。当你的代码如下时,最后的结果可能不是你希望的。
void update_data_for_widget(widget_id w,widget_data& data);
void oops_again(widget_id w)
{
widget_data data;
std::thread t(update_data_for_widget,w,data);
display_status();
t.join();
process_widget_data(data);
}
上述代码首先将data复制到线程空间中,然后再将线程空间中data值的引用传递到update_data_for_widget()函数中,而不是oop_again函数中原data的引用。要想确保传递的是原data的引用,需要用到新的基础设施:std::ref()。就像下面的代码这样:
std::thread t(update_data_for_widget,w,std::ref(data));
这样,你的代码就能正常工作了。

管理一个线程

(1)C++中,线程不可被拷贝构造和赋值构造,唯一能够使用的是移动构造,因此,想要用一个线程去初始化别一个线程,正确的语法如下:
void some_function();
void some_other_function();
std::thread t1(some_function);
std::thread t2=std::move(t1);
t1=std::thread(some_other_function);
std::thread t3;
t3=std::move(t2);
t1=std::move(t3);
(2)每一个线程都有一个唯一的标识,其类型为std::thread::id, 线程可以通过 std::this_thread::get_id() 函数来获取其id。
(3)细心的读者可以注意到了开始线程的代码片段里用到了线程的成员函数join(),这个函数用于等待线程的结束,否则代码将阻塞在join()函数的调用处。这是因为每个进程都有一个主线程,当主线程结束时,这个进程就会终止,系统最后会回收这个进程的资源。当主线程结束时,其他线程就算没有结束,也会被结束。为了使得其他线程运行结束后进程再终止,由于无法主动获知其他线程会在何时结束,所以必须要主线程中等待其他线程的结束。其他的相关成员函数还有joinable()和detach(),当一个线程detach时,将无法join(等待),而线程是是否可join,可以用joinable()函数来检测。当线程调用detach()函数或者join()函数后,joinable()函数都将返回false。




  • 5
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

一尺丈量

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值