首页 > 编程语言 >C++11 多线程(std::thread)实例

C++11 多线程(std::thread)实例

时间:2023-11-24 16:56:01浏览次数:50  
标签:11 std include 17 thread int C++ 多线程

C++11的std::thread
在C中已经有一个叫做pthread的东西来进行多线程编程,但是并不好用 (如果你认为句柄、回调式编程很实用,那请当我没说),所以c++11标准库中出现了一个叫作std::thread的东西。

std::thread常用成员函数
构造&析构函数

举个栗子

例一:thread的基本使用

 1 // Compiler: MSVC 19.29.30038.1
 2 // C++ Standard: C++17
 3 #include <iostream>
 4 #include <thread>
 5 using namespace std;
 6 void doit() { cout << "World!" << endl; }
 7 int main() {
 8     // 这里的线程a使用了 C++11标准新增的lambda函数
 9     // 有关lambda的语法,请参考我之前的一篇博客
10     // https://blog.csdn.net/sjc_0910/article/details/109230162
11     thread a([]{
12         cout << "Hello, " << flush;
13     }), b(doit);
14     a.join();
15     b.join();
16     return 0;
17 }

那么,为什么会有不同的结果呢?
这就是多线程的特色!

多线程运行时是以异步方式执行的,与我们平时写的同步方式不同。异步方式可以同时执行多条语句。

在上面的例子中,我们定义了2个thread,这2个thread在执行时并不会按照一定的顺序。打个比方,2个thread执行时,就好比赛跑,谁先跑到终点,谁就先执行完毕。

例二:thread执行有参数的函数
 1 // Compiler: MSVC 19.29.30038.1
 2 // C++ Standard: C++17
 3 #include <iostream>
 4 #include <thread>
 5 using namespace std;
 6 void countnumber(int id, unsigned int n) {
 7     for (unsigned int i = 1; i <= n; i++);
 8     cout << "Thread " << id << " finished!" << endl;
 9 }
10 int main() {
11     thread th[10];
12     for (int i = 0; i < 10; i++)
13         th[i] = thread(countnumber, i, 100000000);
14     for (int i = 0; i < 10; i++)
15         th[i].join();
16     return 0;
17 }

 

注意:我说的是有可能。你的运行结果可能和我的不一样,这是正常现象,在上一个例子中我们分析过原因。

这个例子中我们在创建线程时向函数传递了一些参数,但如果要传递引用参数呢?是不是像这个例子中直接传递就行了?

让我们来看看第三个例子:

例三:thread执行带有引用参数的函数
 1 // Compiler: MSVC 19.29.30038.1
 2 // C++ Standard: C++17
 3 #include <iostream>
 4 #include <thread>
 5 using namespace std;
 6 template<class T> void changevalue(T &x, T val) {
 7     x = val;
 8 }
 9 int main() {
10     thread th[100];
11     int nums[100];
12     for (int i = 0; i < 100; i++)
13         th[i] = thread(changevalue<int>, nums[i], i+1);
14     for (int i = 0; i < 100; i++) {
15         th[i].join();
16         cout << nums[i] << endl;
17     }
18     return 0;
19 }

如果你尝试编译这个程序,那你的编译器一定会报错

 这是怎么回事呢?原来thread在传递参数时,是以右值传递的:

// Compiler: MSVC 19.29.30038.1
// C++ Standard: C++17
#include <iostream>
#include <thread>
using namespace std;
template<class T> void changevalue(T &x, T val) {
    x = val;
}
int main() {
    thread th[100];
    int nums[100];
    for (int i = 0; i < 100; i++)
        th[i] = thread(changevalue<int>, ref(nums[i]), i+1);
    for (int i = 0; i < 100; i++) {
        th[i].join();
        cout << nums[i] << endl;
    }
    return 0;
}

这次编译可以成功通过,你的程序输出的结果应该是这样的:

 1 // Compiler: MSVC 19.29.30038.1
 2 // C++ Standard: C++17
 3 #include <iostream>
 4 #include <thread>
 5 using namespace std;
 6 int n = 0;
 7 void count10000() {
 8     for (int i = 1; i <= 10000; i++)
 9         n++;
10 }
11 int main() {
12     thread th[100];
13     // 这里偷了一下懒,用了c++11的foreach结构
14     for (thread &x : th)
15         x = thread(count10000);
16     for (thread &x : th)
17         x.join();
18     cout << n << endl;
19     return 0;
20 }

例四:std::mutex的使用

// Compiler: MSVC 19.29.30038.1
// C++ Standard: C++17
#include <iostream>
#include <thread>
#include <mutex>
using namespace std;
int n = 0;
mutex mtx;
void count10000() {
    for (int i = 1; i <= 10000; i++) {
        mtx.lock();
        n++;
        mtx.unlock();
    }
}
int main() {
    thread th[100];
    for (thread &x : th)
        x = thread(count10000);
    for (thread &x : th)
        x.join();
    cout << n << endl;
    return 0;
}

 1 // Compiler: MSVC 19.29.30038.1
 2 // C++ Standard: C++17
 3 #include <iostream>
 4 #include <thread>
 5 // #include <mutex> //这个例子不需要mutex了
 6 #include <atomic>
 7 using namespace std;
 8 atomic_int n = 0;
 9 void count10000() {
10     for (int i = 1; i <= 10000; i++) {
11         n++;
12     }
13 }
14 int main() {
15     thread th[100];
16     for (thread &x : th)
17         x = thread(count10000);
18     for (thread &x : th)
19         x.join();
20     cout << n << endl;
21     return 0;
22 }

 

 1 // Compiler: MSVC 19.29.30038.1
 2 // C++ Standard: C++17
 3 #include <iostream>
 4 #include <thread>
 5 #include <future>
 6 using namespace std;
 7 int main() {
 8     async(launch::async, [](const char *message){
 9         cout << message << flush;
10     }, "Hello, ");
11     cout << "World!" << endl;
12     return 0;
13 }

 1 // Compiler: MSVC 19.29.30038.1
 2 // C++ Standard: C++17
 3 #include <iostream>
 4 // #include <thread> // 这里我们用async创建线程
 5 #include <future> // std::async std::future
 6 using namespace std;
 7 
 8 template<class ... Args> decltype(auto) sum(Args&&... args) {
 9     // C++17折叠表达式
10     // "0 +"避免空参数包错误
11     return (0 + ... + args);
12 }
13 
14 int main() {
15     // 注:这里不能只写函数名sum,必须带模板参数
16     future<int> val = async(launch::async, sum<int, int, int>, 1, 10, 100);
17     // future::get() 阻塞等待线程结束并获得返回值
18     cout << val.get() << endl;
19     return 0;
20 }

例八:void特化std::future
 1 // Compiler: MSVC 19.29.30038.1
 2 // C++ Standard: C++17
 3 #include <iostream>
 4 #include <future>
 5 using namespace std;
 6 void count_big_number() {
 7     // C++14标准中,可以在数字中间加上单
 8     // 引号 ' 来分隔数字,使其可读性更强
 9     for (int i = 0; i <= 10'0000'0000; i++);
10 }
11 int main() {
12     future<void> fut = async(launch::async, count_big_number);
13     cout << "Please wait" << flush;
14     // 每次等待1秒
15     while (fut.wait_for(chrono::seconds(1)) != future_status::ready)
16         cout << '.' << flush;
17     cout << endl << "Finished!" << endl;
18     return 0;
19 }

// Compiler: MSVC 19.29.30038.1
// C++ Standard: C++17
#include <iostream>
using namespace std;
constexpr long double PI = 3.14159265358979323846264338327950288419716939937510582097494459230781640628;
// 给定圆的半径r,求圆的直径、周长及面积
void get_circle_info(double r, double &d, double &c, double &s) {
    d = r * 2;
    c = PI * d;
    s = PI * r * r;
}
int main() {
    double r;
    cin >> r;
    double d, c, s;
    get_circle_info(r, d, c, s);
    cout << d << ' ' << c << ' ' <<  s << endl;
    return 0;
}

例十一:std::promise的使用

以例七中的代码为基础加以修改:

 1 // Compiler: MSVC 19.29.30038.1
 2 // C++ Standard: C++17
 3 #include <iostream>
 4 #include <thread>
 5 #include <future> // std::promise std::future
 6 using namespace std;
 7 
 8 template<class ... Args> decltype(auto) sum(Args&&... args) {
 9     return (0 + ... + args);
10 }
11 
12 template<class ... Args> void sum_thread(promise<long long> &val, Args&&... args) {
13     val.set_value(sum(args...));
14 }
15 
16 int main() {
17     promise<long long> sum_value;
18     thread get_sum(sum_thread<int, int, int>, ref(sum_value), 1, 10, 100);
19     cout << sum_value.get_future().get() << endl;
20     get_sum.join(); // 感谢评论区 未来想做游戏 的提醒
21     return 0;
22 }

 

 1 #include <iostream>
 2 #include <thread>
 3 #include <atomic>
 4 using namespace std;
 5 atomic_bool ready = 0;
 6 // uintmax_t ==> unsigned long long
 7 void sleep(uintmax_t ms) {
 8     this_thread::sleep_for(chrono::milliseconds(ms));
 9 }
10 void count() {
11     while (!ready) this_thread::yield();
12     for (int i = 0; i <= 20'0000'0000; i++);
13     cout << "Thread " << this_thread::get_id() << " finished!" << endl;
14     return;
15 }
16 int main() {
17     thread th[10];
18     for (int i = 0; i < 10; i++)
19         th[i] = thread(::count);
20     sleep(5000);
21     ready = true;
22     cout << "Start!" << endl;
23     for (int i = 0; i < 10; i++)
24         th[i].join();
25     return 0;
26 }

 转自:https://blog.csdn.net/sjc_0910/article/details/118861539

标签:11,std,include,17,thread,int,C++,多线程
From: https://www.cnblogs.com/Jack-Elvis/p/17854076.html

相关文章

  • Flink实战(11)-Exactly-Once语义之两阶段提交
    0大纲[ApacheFlink]2017年12月发布的1.4.0版本开始,为流计算引入里程碑特性:TwoPhaseCommitSinkFunction。它提取了两阶段提交协议的通用逻辑,使得通过Flink来构建端到端的Exactly-Once程序成为可能。同时支持:数据源(source)和输出端(sink)包括ApacheKafka0.11及更高版本。它提......
  • Linux下Oracle11G数据备份恢复(RMAN)
    数据库安装参考步骤1--14https://www.cnblogs.com/baixisuozai/p/17852235.html创建初始pfile文件$viminit.umpay.ora文件内容:umpay.__java_pool_size=4194304umpay.__large_pool_size=4194304umpay.__oracle_base='/DataBase/app/oracle'#ORACLE_BASEsetfromenv......
  • 2023-11-23
    2023-11-23集合体系结构​​​​‍Collection接口和常用方法常用方法add()添加单个元素remove()删除指定元素contains()查找元素是否存在size()获取元素个数isEmpty()判断是否为空clear()清空addAll()添加多个元素containsAll()查找多个元素是否存在remov......
  • 11.24每日总结
    importmatplotlibasmatplotlibimportnumpyasnpimportpandasaspdimportseabornassnsfrompandasimportDataFrame,Series#可视化显示在界面#matplotlibinlineimportmatplotlibimportmatplotlib.pyplotaspltfromwordcloudimportSTOPWORDS,......
  • std::thread方法join与detach
    1、std::joinstd::join是std::thread类的成员函数之一,用于等待线程的执行完成。#include<iostream>#include<utility>#include<thread>#include<chrono>#include<atomic>voidprocess(std::stringstr_info){for(inti=0;i<500;++i)......
  • 《信息安全系统设计与实现》学习笔记11
    《信息安全系统设计与实现》学习笔记11第13章TCP/IP和网络编程摘要第一部分论述了TCP/IP协议及其应用,具体包括TCP/IP栈、IP地址、主机名、DNS、IP数据包和路由器介绍了TCP/IP网络中的UDP和TCP协议、端口号和数据流阐述了服务器-客户机计算模型和套接字编程接口......
  • MySQL将'20231124'转换为'yyyy/MM/dd'格式
    可以使用STR_TO_DATE函数将一个字符串转换为日期,并使用DATE_FORMAT函数将日期格式化为指定的格式SELECTDATE_FORMAT(STR_TO_DATE('20231124','%Y%m%d'),'%Y/%m/%d');解释一下上述语句的步骤:STR_TO_DATE('20231124','%Y%m%d')将字符串"20231124"转换为日期......
  • C# 接口隔离,反射 2023年11月20日
    1.1接口隔离接口的隔离,对''胖'接口进行拆分单一职责原则接口的显示接口实现(c#独有的语言特性)dependencyInjection,依赖注入框架包适当使用接口泛型,partial类,枚举,结构泛型:泛化数据类型泛型的特化:指定类型泛型委托和lambda表达式partial类$符号的......
  • RTL8211EG硬件设计要点
    RTL8211EG硬件问题解决办法问题一:RTL8211在RGMII模式下跑千兆失败的问题1、 连接网线后与PC自协商到100M。原因:RTL8211EG芯片内部自带DCDCBUCK降压电路,需要外置电感电容才能输出稳定的1.05V电压提供给芯片的内核工作。对于电感和电容,要选择手册推荐的型号,如图1.1所示。V2板由......
  • Spring_2023_11_24_2 Spring整合mybatis--Spring中的事务管理(注解形式)
    Spring整合mybatis--Spring中的事务管理(注解形式)application.xml<?xmlversion="1.0"encoding="UTF-8"?><beansxmlns="http://www.springframework.org/schema/beans"xmlns:tx="http://www.springframework.org/schema/tx&quo......