zoukankan      html  css  js  c++  java
  • 四、创建多线程、数据共享

    一、创建、等待多线程

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

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

    把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 }

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

    下面请看互斥量!

  • 相关阅读:
    HTML <h1>
    HTML <body> 标签
    如何挑选深度学习 GPU?
    视频动作定位的分层自关注网络:ICCV2019论文解析
    三维点云去噪无监督学习:ICCV2019论文分析
    摄像头定位:ICCV2019论文解析
    深度学习扫地机器人
    细粒度语义分割:ICCV2019论文解析
    目标形体形状轮廓重建:ICCV2019论文解析
    2-2.5-3D的室内场景理解
  • 原文地址:https://www.cnblogs.com/pacino12134/p/11232011.html
Copyright © 2011-2022 走看看