C++ 多线程

在c++11中,标准库增添了多线程的相关,方便了我们的很多操作,我们只需要在头文件引入 thread ,就可以使用其中的方法。

创建线程
我们只需要使用thread类就可以完成一个线程的创建,thread需要传入参数,我们必须给他一个可调用的对象,这个对象可以是一个函数,lambda表达式,也可以是类对象.

 thread mythread(myfunction);

如果我们传入的这个函数,或者这个对象构造需要参数,我们可以同时将参数跟在之后传入thread就好。

 thread mythread(myfunction,num1);

完成线程的创建后,当前线程并不会马上打断主线程的执行,开始执行,而是需要我们使用join函数,来完成加入

mythread.join();

调用join后 主线程会进入等待阶段,并执行我们创建的线程,由我们传入的可调用对象入口,开始执行,如我们上面传入了myfunction,那么接下来主线程会暂停执行,然后进入到我们书写的myfunction函数中,开始执行,函数执行完毕后,主线程继续开始完成执行。

我们也可以使用detach函数来完成当前已创建的线程的执行,但是使用detach会造成很多的问题需要我们去考虑。

mythread.detach();

使用detach表示我们将该线程和主线程分离开来,即主线程不需要等待子线程的执行,两个线程会互相争夺cpu来完成自己的执行,但是主线程更占主导地位,因为主线程一旦终结,我们的子线程也会随之终结,不管其执行到了什么程度,这样就引入了很多的问题。

你应该在创建一个线程后,在其被析构之前,对其调用join或detach函数,否则会抛出异常。

你可以使用jionanbe函数,来查看是否线程已经join和detach,返回值为thre 或 false。

在创建线程并使用detach时,要注意传入的线程执行入口是否含有指针变量或者引用,因为使用detach后主线程并不会保证子线程一定完整的执行完,因此我们在主线程的指针和引用在主线程结束时,就被析构和释放了,如果这个时候子线程中还有对这些对象和变量的操作,可想而知,一定是会发生异常的。

在使用detach时,我们可以传入值,子线程会将该值拷贝一份进行操作,因此子线程中不需要在意主线程是否释放该值,我们可以传入类对象,这个对象在传入时会调用类的拷贝构造函数,生成一个拷贝传入子线程,因此我们在子线程中的操作都是对其拷贝操作,也不用担心主线程中的对象是否已经被析构,关于这些,可以自己在程序用实现一下,用输出观察后可以清楚得知这些内容。我们还可以利用线程id的显示,使用方法this_thread::get_id(),来得到线程的id,可以更方便我们观察到哪些对象是在哪个线程中得到了析构和构造。

当我们不想子线程对我们的传入参数和对象进行拷贝,而就是希望在原本的地址上进行操作时,在保证线程的安全下,我们可以在thread中的参数中,加上std::ref(参数名);使用这种方法,就相当于我们可以在子线程中对该参数进行修改,并将修改的值返回给主线程。

我们也可以传入类的成员的函数指针和智能指针作为子线程入口。

thread mythread(&myclass::function,&threadobj, 15);
//第一参数为成员函数名,第二参数为类的对象,是否有第三参数取决于成员函数是否需要传入参数

其中使用 &取地址的操作,就相当于 使用std::ref(threadobj); 旨在我们不需要其进行拷贝。

当我们传入智能指针时,要注意指针的类型,如果是share ptr,我们不需要在创建时对指针进行类型转换,但是如果传入是unique ptr,我们需要对参数进行std::move(unique ptr)操作,这是由于unique ptr的特性所导致的。

thread myobj(mptr_function, sharedptr);
thread myobj(mptr_function, std::move(uniqueptr));

还可以传入lambdas表达式

auto threadlambda = [] {cout << "mythread" << endl; };
thread mythread(threadlambda );
mythread.join();

我们还可以创建多个线程,如使用

vector<thread> mythread;
for (int i = 0; i < 5; i++) 
mythread.push_back(thread(myfunction));

for (auto iter = mythread.begin(); iter != mythread.end(); iter++) {
	//cout << iter->get_id() << endl;
	iter->join();

这样我们就完成了五个线程的创建,并且其入口函数都是myfunction,并且对其用迭代器遍历后使用join开始执行,但要注意我们这样创了多个线程后,子线程之间的执行顺序并不是按照我们创建的顺序来执行的,这关系到后台cpu对于子线程之间的调度,所以如果我们在这些线程中有不同的输出,我们就可以看到其输出顺序是混乱的。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值