C++学习笔记--多线程

本文详细介绍了C++中的多线程编程,包括主线程和子线程的交互、内存共享、线程安全、避免死锁、Unique Lock、条件变量、Future、Promise和异步操作等关键概念和实践技巧,旨在帮助开发者理解和掌握多线程编程。
摘要由CSDN通过智能技术生成

线程与进程优缺点对比:
多线程开销小,但难于管理,且不能用于分布式系统;
多进程开销大,操作系统会进行一部分管理,因此用户管理就比较简单,可用于分布式;
通常多线程和多进程结合使用。
参考资料:http://edu.csdn.net/course/detail/2303/35894?auto_start=1
代码实例:

1 最简单的多线程

#include <iostream>
#include <thread>

void function_1()
{
    std::cout <<"www.oxox.work"<<std::endl;
}

int main()  //主线程
{
    std::thread t1(function_1); //创建并初始化一个线程,且线程t1创建完之后就开始运行
    //t1.detach();  //主线程和t1线程互不影响,detach可以使主线程不等待t1线程结束即可运行,这样会使得程序的运行结果没有内容输出,因为主线程还没有等到t1输出内容就结束了。线程被deatch之后就不能再join了,如果再join,编译不会报错,但是运行会报错
    if(t1.joinable())    //如果执行了t1.detach(),t1.joinable()为false
    {
        t1.join();  //主线程将等待t1线程结束后再运行
    }

    return 0;
}

2 主线程和子线程交叉运行

#include <iostream>
#include <thread>

using namespace std;
void function_1()
{
    cout <<"www.oxox.work"<<endl;
}

class Factor
{
public:
    void operator()()
    {
        for(int i = 0; i > -100; --i)
        {
            cout << "from t1: " << i << endl;
        }
    }
};

int main()  //主线程
{
    //std::thread t1(function_1);   //使用函数创建并初始化一个线程,且线程开始运行
    Factor fct;
    std::thread t1(fct);    //使用函数对象创建并初始化一个线程

    try
    {
        for(int i = 0; i < 100; ++i)
        {
            cout << "from main: " << i << endl;
        }
    }
    catch(...)  //上面的for循环属于主线程,如果上面抛出异常,但是没有try catch,主线程终止,t1线程也终止了,这样是非线程安全的。添加try catch之后,即使主线程异常,t1线程也能正常执行结束
    {
        t1.join();  //主线程将等待t1线程结束后再运行
        throw;
    }
    return 0;
}

3 主线程和子线程之间实现内存共享

#include <iostream>
#include <thread>
#include <string>

using namespace std;
void function_1()
{
    cout <<"www.oxox.work"<<endl;
}

class Factor
{
public:
    void operator()(string &s)
    {
        cout << "from t1: " << s << endl;
        s = "I love XuHuanDaXue";
    }
};

int main()  //主线程
{
    string s("I love www.oxox.work");    //string变量s被主线程和t1线程使用,可通过s实现内存共享
    Factor fct;
    //std::thread t1(fct, s);    //这种方式并不能在t1线程中改变s,因为s将被拷贝
        std::thread t1(fct, std::ref(s));   //t1线程可改变s,因为参数是s的引用
    t1.join();
    cout << "from main: " << s.c_str() << endl;    //主线程使用了被t1线程改变的s
    return 0;
}

4 线程移动与线程ID

#include <iostream>
#include <thread>
#include <string>

using namespace std;
void function_1()
{
    cout <<"www.oxox.work"<<endl;
}

class Factor
{
public:
    void operator()(string &s)
    {
        cout << "from t1: " << s << endl;
        s = "I love XuHuanDaXue";
    }
};

int main()  //主线程
{
    string s("I love www.oxox.work");
    Factor fct;
    cout << std::this_thread::get_id() << endl; //获取主线程ID,每个线程都有个ID
    std::thread t1(fct, std::move(s));  //此处s被移动,移动操作比拷贝要高效,比引用要安全
    std::thread t2=std::move(t1);   //线程对象只能被移动,但不能被拷贝,所以必须使用std::move()
    cout << t2.get_id() << endl;    //获取t2线程ID
    //t1.join();
    t2.join();  //t1被移动到t2,t1已经是空的了,所以得使用t2.join()

    cout << "from main: " << s.c_str() << endl;
    cout << std::thread::hardware_concurrency() <<endl; //检测CPU能支持的最大线程数,如果用户创建的线程数超过了CPU能支持的,反而会引起性能下降
    return 0;
}

5 线程安全

下面的代码是非线程安全的,主线程和t1线程将竞争资源cout,只要竞争到资源就随时可以将内容写入到输出流cout,使得输出看起来是下面这样的:

from t1: 0
from t1: -1
from t1: -2
from main: 0
from main: 1
from main: 2
from main: 3
from main: 4
from main: 5
from main: 6
from main: 7
from t1: -3
from t1: -4
from t1: -5

#include <iostream>
#include <thread>
#include <string>

using namespace std;

void function_1()
{
    for(int i = 0; i > -100; --i)
    {
        cout << "from t1: " << i << endl;
    }
}

int main()  //主线程
{
    std::thread t1(function_1);
    for(int i = 0; i < 100; ++i)
    {
        cout << "from main
  • 3
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值