C++多线程编程深度解析

本文深入探讨了C++中的多线程编程,包括线程的基本概念、创建和启动,重点讲解了互斥量、死锁以及如何避免死锁,介绍了单例设计模式下共享数据的保护机制,讲解了读写锁、条件变量以及future和async的使用。通过这些内容,读者可以更好地理解和应用C++的多线程技术。
摘要由CSDN通过智能技术生成

一、线程的基本概念

  1. 每个进程(执行起来的可执行程序)都有一个主线程,主线程随进程默默启动
  2. 线程都要有函数入口,main函数即为主线程的入口
  3. 线程不是越多越好,每个线程需要一个独立的堆栈空间(大约1M),线程切换要保存很多中间状态,耗费时间
  4. 线程是轻量级的进程,一个进程中的线程共享地址空间,全局变量、全局内存、全局引用都可以在线程之间传递,所以多线程的开销远远小于多进程

二、线程的创建和启动

1、范例演示线程运行的开始

线程包含在头文件< thread >中,线程必须指定执行的入口函数,

void myPrint()
{
   
	// this_thread::get_id()可以获取当前执行线程的ID(独一无二)
	cout << "thread id " << this_thread::get_id() << " is starting..." << endl;
	//-------------
	cout << "thread is finished" << endl;
	return;
}

int main()
{
   
	//创建子线程1,指定线程执行入口是myPrint;(2)执行线程
	thread myThread1(myPrint);
	
	//阻塞主线程,当子线程1执行完毕再开始执行
	myThread1.join();

	//子线程1结束后创建子线程2,指定线程执行入口是myPrint;(2)执行线程
	thread myThread2(myPrint);

	//detach后,子线程和主线程失去关联,独立运行,
	//如果主线程先结束,则子线程驻留在后台,由C++运行时库接管
	//所以子线程2的打印不一定可以出现在终端上,取决于它和主线程执行的快慢
	myThread2.detach();
	
	cout << "Hello World!" << endl;
	return 0;
}

2、用对象创建线程

class Stu
{
   
public:
    int age;
    Stu(int i) : age(i)
    {
   
        cout << "Stu的构造函数被执行" << endl;
    }
    Stu(const Stu &stu) : age(stu.age)
    {
   
        cout << "Stu的拷贝函数被执行" << endl;
    }
    ~Stu()
    {
   
        cout << "Stu的析构函数被执行" << endl;
    }
    void operator()()
    {
   
        cout << "我的线程开始运行" << endl;
        //-------------
        //-------------
        cout << "我的线程运行完毕" << endl;
    }
};

int main()
{
   
    // 用对象创建线程
    Stu student1(18); // 执行构造函数
    thread th1(student1); // 执行拷贝函数,将对象student1拷贝一份到子线程中,
    						//所以即便使用detach时,主线程先结束,student1的拷贝对象也还是存在
    th1.join();	//当线程th1结束后,执行被拷贝对象的析构函数

    cout << "I love China1" << endl;

    return 0;	//当主线程结束后,执行student1对象的析构函数
}

3、线程传参详解

线程可以共享进程的内存空间,线程拥有自己独立内存
主线程的值,被拷贝一份到子线程中,即便是引用时,传入的也是值的副本,也就是说子线程中的修改影响不了主线程中的值
注意:1、指针传参时,很多资料显示,子线程和主线程的参数地址相同,但是,自测是不同的地址!
2、引用传参时,也是拷贝,参数地址在子线程和主线程中不一致

void test(int ti, char* tj, const int &tk) //在引用前必须加const,否则会出错,可能是因为临时对象具有常性
{
   
    cout << "子线程开始" << endl;
    //ti的内存地址0x292fcf0{4},tj的内存地址0x292fcf8 {"this is a test"}
    //tk的内存地址0xf86588 {5}
    cout << &ti << " " << &tj << " " << &tk << endl;
    cout << "子线程结束" << endl;
    return;
}
int main()
{
   
    cout << "主线程开始" << endl;
    //i的内存地址0x001efdfc {4},j的内存地址0x001efdf0 {"this is a test"}, 
    //k的内存地址0x001efef4 {5}
    int i = 4;
    char j[] = "this is a test";
    int k = 5;
    thread t(test, i, j, k);	// 线程传参格式
    t.join();
    cout << "主线程结束!" << endl;
    return 0;
}

如果需要将在子线程中的修改能够反映到主线程中,需要使用std::ref(),此时用于接收ref()的那个参数前不能加const。

class A {
   
public:
    int ai;
    A(int i) : ai(i) {
    }
};
//接收ref()的那个参数前不能加const,因为我们会改变那个值
void test(int& ti, const A& t)
{
   
    cout << "子线程开始" << endl;
    cout << ti << " " << t.ai << endl; // 4 5
    ti++;
    cout << "子线程结束" << endl;
    return;
}
int main()
{
   
    cout << "主线程开始" << endl;
    int i 
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值