多线程学习笔记1

6 篇文章 0 订阅
6 篇文章 7 订阅

多线程

注 : 看着视频教程的手写笔记 , 如有错误 , 评论更正

#include<iostream>
#include<cstdio>
#include<thread>
#include<stdlib.h> 
using namespace std;

void myprint(){
    cout<<"子线程开始了"<<endl;
    cout<<"子线程结束了"<<endl;
}

int main(){
    cout<<"主线程开始啦"<<endl;

    thread mytobj(myprint);//创建了线程,并开始执行
    //mytobj.join();//主线程阻塞到这里,等待该子线程结束才继续执行
    //mytobj.detach();

    cout<<"主线程结束啦"<<endl;

    return 0;
}
thread
void 线程函数名(){}
thread 线程对象名(线程函数名);//创建了线程,并开始执行
join()
线程对象.join();//主线程阻塞到这里,等待该子线程结束才继续执行

一个书写良好的程序,应该是主线程等待子线程执行完毕后,自己才能退出

detach()
线程对象.detach();//主线程与子线程分离

detach() : 分离,主线程不与子线程汇合了 , 主线程不必等待子线程结束

一旦detach()之后,与这个主线程关联的thread对象就会失去与这个主线程的关联关系 , 此时这个子线程就会驻留在后台运行

相当于这个子线程被c++运行时库接管,当该子线程运行结束,有运行时库清理该线程的相关资源(守护线程)

一旦detach了,就不能再用join了,系统会报异常

应用较少

joinable()
if(线程对象.joinable()){
        线程对象.join();//可以
        //线程对象.detach();
}

判断是否可以成功使用join()或detach()的

返回 true(就可以joindetach) 或者flase

类对象作为线程函数
class A{
public:
	void operator()(){
		cout<<"子线程开始了"<<endl;
    	cout<<"子线程结束了"<<endl;
	}
};
int main(){
	A a;
	thread myjob(a);
    thread myjob( ref(a) );//传引用.不能用detach
	myjob.join();
	return 0;
}

类对象使用detach()可能会出bug,比如子线程引用了主线程的某些变量,当主线程结束后,资源就销毁了,但子线程还继续调用主线程资源,就会有bug产生,指针也很可能产生问题

当调用detach() , a对象便被复制到(拷贝构造函数)了子线程当中去 , 当主线程结束,主线程中的a便被销毁了,但子线程中的复制的a依旧存在,join()类似

子线程执行完了 , 子线程中的对象便执行析构函数,释放内存

lambda表达式
auto mylamthread = [] {
        cout<<"我的线程开始执行了"<<endl;

        cout<<"我的线程执行结束了"<<endl;
    };
    thread myjob(mylamthread);
    myjob.join();
	//myjob.detach();
传参
void print(int t,char s ){
    cout<<t<<endl;
    cout<<s<<endl;
}
thread myjob(print,t,s);
void print(const int &t,char *s ){    cout<<t<<endl;    cout<<s<<endl;}int main(){    int t=1;    int &mt=t;    char s[]="i love the world";    thread myjob(print,t,s);    myjob.detach();    cout<<"主线程结束"<<endl;    return 0;}

detach()时 , 主线程不再等待子线程,当主线程结束 , 资源被释放 , 子线程中的指针指向的内存没有了 , 会出bug , 但是引用不会 , 因为这里的引用都是假引用 , 照样回创建变量.

假设我们将这里改成

void print(const int &t,const string &s )

还是可能会出问题,因为我们不知道s是什么时候转成string的 , 可能在main执行结束之后 , 那么就会出bug

最佳解决方案

void print(const int &t,const string &s )thread myjob(print,t,string(s));

这样就可以了 , 这样就是说我们先进行了类型转换,然后再调用进行thread的构造函数,就即时地将这里的参数给了一份给子线程

这里的调用情况为 :

1,调用了string的转换构造函数,生成临时对象

2,thread构造函数

3,调用拷贝构造函数生成子线程中的string对象

hint

若传递int这个简单类型,建议都不写引用

如果传递对象 , 避免隐式类型转换 . 全部都在创建线程这一行就构造出临时对象来 , 然后在函数参数里 , 用引用来接 , 否者会多构造出一次对象

线程id
std::this_thread::get_id()

概念 : id是一个数字 , 每个线程(不管是主线程还是子线程) 实际上都是一个数字 , 而且每个线程id都不同

线程id可以用c++标准库里的函数来获取 .

std::this_thread::get_id()来获取

std:ref( 参数)
void myprint( int &a )/**********************/   	int x=3;    thread myjob(myprint,std::ref(x));

ref可以使线程真的引用

参数是智能指针
void myprint( unique_ptr<int> a_ptr )int main(){    unique_ptr<int> b_ptr(new int(3));	thread myjob(myprint,move( b_ptr ) );    myjob.join();    if( b_ptr==nullptr ){//智能指针,b_ptr为空        cout<<"b_ptr is empty!!!"<<endl;    }    return 0;}

要用join,不要用detach,因为new在主线程,主线程结束new的资源就被释放了

成员函数做子线程函数
class A{public:    int val;    A(){}    A(int item):val(item){}    A(const A &a):val(a.val){cout<<"is copy !!!"<<endl;}    ~A(){}    void mythread(int item){        cout<<"sun_start"<<endl;        cout<<"sun_end"<<endl;    }};int main(){    cout<<"main_start"<<endl;    A a(666);    thread myjob( &A::mythread,a,19 );//这个可以用detach    thread myjob( &A::mythread,ref(a),19 );//真引用,这个不能用detach    thread myjob( &A::mythread,&a,19 );//等价与ref写法,但不安全    myjob.join();    cout<<"main_end"<<endl;    return 0;}

只要是传值(拷贝构造) , 就可以用detach

学习心得

可以通过打印参数地址的方法判断detach是否安全 , 比较参数是引用的还是再拷贝的 , 当然如果是new在函数的内存,传递时只进行了浅拷贝就不能detach了.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值