IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> C++知识库 -> C++多线程快速入门(一):基本&常用操作 -> 正文阅读

[C++知识库]C++多线程快速入门(一):基本&常用操作

case1:创建线程1 join、detach

创建线程,并等该线程执行完毕,并且打印两个线程的id

#include <iostream>
#include <thread>
using namespace std;
void func() {
    cout << "hello , this is my thread, thread id is " << this_thread::get_id() << endl;
}
int main() {
    thread th = thread(func);
    th.join();
    cout << "this is main thread and its id is " << this_thread::get_id() << endl;
}

执行结果如下:

C:\Users\LENOVO\CLionProjects\untitled\cmake-build-debug\untitled.exe
hello , this is my thread, thread id is 2
this is main thread and its id is 1

Process finished with exit code 0

使用detach,放弃对该线程的控制:

#include <iostream>
#include <thread>

using namespace std;

void func() {
    cout << "hello , this is my thread, thread id is " << this_thread::get_id() << endl;
}
int main() {
    thread th = thread(func);
    th.detach();
    // 如果我们此时不再关系该线程的运行情况的话可以使用detach
    cout << th.joinable() << endl;
    cout << "this is main thread and its id is " << this_thread::get_id() << endl;
}

运行结果:

C:\Users\LENOVO\CLionProjects\untitled\cmake-build-debug\untitled.exe
0
this is main thread and its id is 1
hello , this is my thread, thread id is 2

Process finished with exit code 0

case2:创建线程2 线程传参 传值或者传引用

传值

#include <iostream>
#include <thread>

using namespace std;

void func(string s) {
    cout << "hello , this is my thread, thread arg is " << s << endl;
}
int main() {
    thread th = thread(func, "test");
    th.join();
    cout << "this is main thread and its id is " << this_thread::get_id() << endl;
}

打印结果如下:

C:\Users\LENOVO\CLionProjects\untitled\cmake-build-debug\untitled.exe
hello , this is my thread, thread arg is test
this is main thread and its id is 1

Process finished with exit code 0

传引用

#include <iostream>
#include <thread>

using namespace std;

void func(string& s) {
    cout << (&s) << endl;
    cout << "hello , this is my thread, thread arg is " << s << endl;
}
int main() {
    string str = "test";
    thread th = thread(func, ref(str));
    cout << (&str) << endl;
    th.join();
    cout << "this is main thread and its id is " << this_thread::get_id() << endl;
}

打印结果如下:

C:\Users\LENOVO\CLionProjects\untitled\cmake-build-debug\untitled.exe
0x62fd10
0x62fd10
hello , this is my thread, thread arg is test
this is main thread and its id is 1

Process finished with exit code 0

case3:创建线程 线程传参 functional object作为参数

关于仿函数的定义可以看:仿函数
如果单纯地将逻辑函数传入thread,在函数逻辑比较复杂的时候不太好。
将函数封装到类的内部,可以赋予一定的封装性,并且可以在类内部创建例如map的数据结构来记录函数运行的状态。
仿函数、不带参

#include <iostream>
#include <thread>

using namespace std;

// functional object
struct A {
    void operator()() {
        cout << "I'm A" << endl;
    }
};
void show() {
    cout << "I'm show" << endl;
}
int main() {
    show();
    A a;
    a();    // 等价于 a.operator()();
    // 我们把这种object称为callable的object ,又称为仿函数
    thread thread1 = thread(A());
    thread1.join();
    return 0;
}

打印结果如下:

C:\Users\LENOVO\CLionProjects\untitled\cmake-build-debug\untitled.exe
I'm show
I'm A
I'm A

Process finished with exit code 0

仿函数、带参

#include <iostream>
#include <thread>

using namespace std;

// functional object
struct A {
    void operator()(int num) {
        for (int i = 0; i < num; i++) {
            cout << "I'm A" << i << endl;
        }
    }
};

int main() {
    int num = 10;
    thread thread1 = thread(A(), num);
    for (int i = 0; i < num; i++) {
        cout << "I'm main" << i << endl;
    }
    thread1.join();
    return 0;
}

打印结果如下,是乱序的,符合多线程特性
并且 cout 并不是线程安全的,所以可以发现,有乱码的样子

C:\Users\LENOVO\CLionProjects\untitled\cmake-build-debug\untitled.exe
I'm mainI'm A00

I'm A1
I'm A2
I'm A3
I'm AI'm main41

I'm mainI'm A25

I'm mainI'm A36

I'm AI'm main47

I'm main5
I'm mainI'm A86

I'm mainI'm A97

I'm main8
I'm main9

Process finished with exit code 0

lambda函数作为参数

#include <iostream>
#include <thread>

using namespace std;

int main() {
    string s = "test";
    thread f = thread([&s](int a,int b) {
        cout << s << endl;
        cout << a + b << endl;
    }, 2, 3);
    f.join();
    return 0;
}

打印结果:

C:\Users\LENOVO\CLionProjects\untitled\cmake-build-debug\untitled.exe
test
5

Process finished with exit code 0

case4:观察多线程程序加速计算

#include <iostream>
#include <thread>

using namespace std;

// 测量一个函数的运行时间
template <class T>
void measure(T&& func) {
    using namespace std::chrono;
    auto start = system_clock::now();
    // func
    func();
    duration<double> diff = system_clock::now() - start;
    cout << "执行了" << diff.count() << "秒" << endl;
}

// 求和函数[start,end)
void sum(long start, long end, long& ans) {
    long s = 0;
    for(auto i = start; i < end; i++) {
        s += i;
    }
    ans = s;
}

const long S = 100000000;

int main() {
    // 测量一下把工作分摊给两个线程做的时间
    measure([](){
        long ans1, ans2;
        thread t1 = thread(sum, 0, S >> 1, std::ref(ans1));
        thread t2 = thread(sum, S >> 1, S, std::ref(ans2));
        t1.join();
        t2.join();
        cout << "ans = " << ans1 + ans2 << endl;
    });
    // 测量一下单线程工作时间
    measure([](){
        long ans;
        sum(0, S, ans);
        cout << "ans = " << ans << endl;
    });
    return 0;
}

打印结果:

C:\Users\LENOVO\CLionProjects\untitled\cmake-build-debug\untitled.exe
ans = 887459712
执行了0.13546秒
ans = 887459712
执行了0.240006秒

Process finished with exit code 0

当然这里有一个细节:
如果在多线程程序中我们传入了一个ref引用,在线程程序中我们最好不要直接对这个ref值操作,而是采用一个临时变量,例如上面的程序中我们就使用了一个临时变量s,对s进行累加后再把值赋给ans。这样会提高程序运行效率。

case5:future + get 获取并发结果

future包裹线程运行结果,使用方法如下:
由于我们线程函数的结果是long,所以首先定义future<long>

#include <iostream>
#include <thread>
#include <future>
#include <vector>

using namespace std;

// 测量一个函数的运行时间
template <class T>
void measure(T&& func) {
    using namespace std::chrono;
    auto start = system_clock::now();
    // func
    func();
    duration<double> diff = system_clock::now() - start;
    cout << "执行了" << diff.count() << "秒" << endl;
}

// 求和函数[start,end)
long sum(long start, long end) {
    long s = 0;
    for(auto i = start; i < end; i++) {
        s += i;
    }
    return s;
}

const long S = 100000000;

int main() {
    // 测量一下把工作分摊给 threadNums 个线程做的时间
    measure([](){
       const long threadNums = 8;
       vector<future<long>> vec;
       vec.reserve(threadNums);
       for (int i = 0; i < threadNums; i++) {
           vec.push_back(async(sum, (S / threadNums) * i, (S / threadNums) * (i + 1)));
       }
       long ans = 0;
       // get 阻塞式地拿到并发结果
       for (int i = 0; i < threadNums; i++) {
           ans += vec[i].get();
       }
       cout << "ans = " << ans << endl;
    });
    // 测量一下单线程工作时间
    measure([](){
        long ans = sum(0, S);
        cout << "ans = " << ans << endl;
    });
    return 0;
}

运行结果如下:

C:\Users\LENOVO\CLionProjects\untitled\cmake-build-debug\untitled.exe
ans = 887459712
执行了0.0521455秒
ans = 887459712
执行了0.250044秒

Process finished with exit code 0

case6:互斥锁

多个线程访问同一个值并且对其修改,会导致数据竞争。:

#include <iostream>
#include <thread>
#include <future>
#include <vector>

using namespace std;
// 测量一个函数的运行时间
template <class T>
void measure(T&& func) {
    using namespace std::chrono;
    auto start = system_clock::now();
    // func
    func();
    duration<double> diff = system_clock::now() - start;
    cout << "执行了" << diff.count() << "秒" << endl;
}

std::mutex mtx;
// 求和函数 线程安全的
void sum(long& s) {
    mtx.lock();
    for (int i = 0; i < 100000; i++) {
        s++;
    }
    mtx.unlock();
}

int main() {
    // 测量一下把工作分摊给 threadNums 个线程做的时间
    measure([](){
        vector<thread> v;
        long s = 0;
        for (int i = 0; i < 4; i++) {
             v.emplace_back(std::thread(sum, std::ref(s)));
         }
        for (int i = 0; i < 4; i++) {
            v[i].join();
        }
        cout << "ans " << s << endl;
    });
    measure([](){
        long s = 0;
        for (int i = 0; i < 4; i++) {
            sum(s);
        }
        cout << "ans " << s << endl;
    });
    return 0;
}

测试结果:

C:\Users\LENOVO\CLionProjects\untitled\cmake-build-debug\untitled.exe
ans 400000
执行了0.0141654秒
ans 400000
执行了0.0155926秒

Process finished with exit code 0

笔记参考:
C++多线程快速入门

  C++知识库 最新文章
【C++】友元、嵌套类、异常、RTTI、类型转换
通讯录的思路与实现(C语言)
C++PrimerPlus 第七章 函数-C++的编程模块(
Problem C: 算法9-9~9-12:平衡二叉树的基本
MSVC C++ UTF-8编程
C++进阶 多态原理
简单string类c++实现
我的年度总结
【C语言】以深厚地基筑伟岸高楼-基础篇(六
c语言常见错误合集
上一篇文章           查看所有文章
加:2021-10-22 10:47:24  更:2021-10-22 10:49:39 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 3:20:55-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码