四、创建多线程、数据共享

一、创建、等待多线程

后创建的线程不一定比先创检的线程慢。

多个线程的执行顺序是乱的,跟操作系统内部的线程调度机制有关。

把thread放入到容器里进行管理和调度。

 1 #include <iostream>
 2 #include <thread> //线程
 3 #include <vector>
 4 using namespace std;
 5 
 6 void myprt(int num){
 7     cout << "线程开始,线程编号:" << num << endl;
 8     cout << "线程结束,线程编号:" << num << endl;
 9     return;
10 }
11 int main(){
12     //创建多个线程,线程入口函数统一使用myprt
13     vector<thread> mythreads;
14     for(int i=0;i<10;i++){
15         mythreads.push_back(thread(myprt,i));//创建并执行线程
16     }
17     for(auto iter=mythreads.begin();iter!=mythreads.end();iter++){
18         iter->join();//等待10个线程都返回
19     }
20     cout<<"main end"<<endl;
21     return 0;
22 }

二、数据共享

1、只读数据

 1 #include <iostream>
 2 #include <thread> //线程
 3 #include <vector>
 4 using namespace std;
 5 
 6 vector<int> g_v={1,2,3};//共享数据是安全稳定的
 7 void myprt(int num){
 8     //cout << "线程开始,线程编号:" << num << endl;
 9     //cout << "线程结束,线程编号:" << num << endl;
10     cout<< "id:"<<std::this_thread::get_id()<<"的线程打印g_v的值"<<g_v[0]<<endl;
11     return;
12 }
13 int main(){
14     //创建多个线程,线程入口函数统一使用myprt
15     vector<thread> mythreads;
16     for(int i=0;i<10;i++){
17         mythreads.push_back(thread(myprt,i));//创建并执行线程
18     }
19     for(auto iter=mythreads.begin();iter!=mythreads.end();iter++){
20         iter->join();//等待10个线程都返回
21     }
22     cout<<"main end"<<endl;
23     return 0;
24 }

2、有读有写

比如两个线程写,8个线程读,肯定会崩溃。

由于任务切换,会导致各种诡异的事情发生。

最简单的不崩溃方法:读的时候不写,写的时候不读,多个线程不能同时写,多个线程不能同时读;

三、共享数据的保护案例代码

c++解决多线程保护共享数据问题的概念:互斥量!

 1 #include <iostream>
 2 #include <thread> //线程
 3 #include <vector>
 4 #include <list>
 5 /*
 6 网络游戏服务器
 7 创建两个线程,一个线程收集玩家命令(用一个数字代表玩家命令),并把命令数据写到一个队列中;
 8 另一个线程从队列中取出玩家发送来的命令,解析,然后执行玩家需要的动作。
 9 list:频繁顺序插入和删除数据时效率高;
10 vector:频繁随机插入和删除数据时效率高;
11 准备使用成员函数来作为线程函数
12 */
13 using namespace std;
14 class A{
15 public:
16     //把收到的消息(玩家命令)让入到一个队列中的线程函数
17     void InMsgQue(){
18         for(int i=0;i<100;i++){
19             cout<<"InMsgQue执行,插入一个元素"<<i<<endl;
20             MyQue.push_back(i);//假设i就是命令
21         }
22 
23     }
24     //把数据从消息队列中取出来的线程函数
25     void OutMsgQue(){
26         for(int i=0;i<100;i++){
27             if(!MyQue.empty()){
28                 //消息不空
29                 int command = MyQue.front();//返回第一个元素,但是不检查元素是否存在,所以要if先判断
30                 MyQue.pop_front();
31                 //接下来就考虑处理数据.........
32             }
33             else{
34                 cout << "OutMsgQue执行,但是消息队列为空"<<i << endl;
35             }
36 
37         }
38         cout<<"end"<<endl;
39     }
40 private:
41     list<int> MyQue;
42 };
43 
44 int main(){
45     A myobj;
46     std::thread myout(&A::OutMsgQue,&myobj);
47     std::thread myin(&A::InMsgQue,&myobj);//必须市引用,才能保证线程用的是同一个对象
48     myout.join();
49     myin.join();
50     cout<<"main end"<<endl;
51     return 0;
52 }

上面代码有个问题,就是收集命令和取出命令是对共享队列同时进行的,同时对同一个数组进行修改,会导致崩溃。

下面请看互斥量!

原文地址:https://www.cnblogs.com/pacino12134/p/11232011.html