C++11多线程编程 4.创建多个线程,数据共享问题分析,案例代码

tech2025-04-07  8

#include<iostream> #include<thread> #include<vector> #include<list> using namespace std; //线程入口函数 vector<int>v = { 1,2,3 };//共享数据 void myprint(int num) {     cout << "线程开始执行了,线程编号=" << std::this_thread::get_id() << "     " << num << endl;     return; } void myprint2(int num) {     cout << "id:" << std::this_thread::get_id() << "  " << v[0] << v[1] << v[2] << endl;     return; } class A { public:     //把收到的消息(玩家命令)入到一个队列的线程。     void inMsgRecvQueue() {         for (int i = 0; i < 10000; i++) {             cout << "inMsgRecvQueue()执行,插入一个元素" << i <<endl;             msgRecvQueue.push_back(i);//假设数字i就是玩家收到的命令,我直接弄到消息队列里面         }     }     //把数据从消息队列中取出的线程:     void outMsgRecvQueue() {         for (int i = 0; i < 10000; i++) {             if (msgRecvQueue.empty()) {                 //消息队列不会空                 int command = msgRecvQueue.front();//返回第一个元素,但不检查元素是否存在                 msgRecvQueue.pop_front();//移除第一个元素。但不返回。                 //这里就考虑处理数据.......             }             else             {                 cout << "outMsgRecvQueue()执行,但目前消息队列为空" << i << endl;             }         }         cout << "end" << endl;     } private:     std::list<int>    msgRecvQueue;//容器,专门用于代表玩家给咱们发送的命令 }; int main() {      /*    (1)创建和等待多个线程      *    (2)数据共享问题      *        (2.1)只读的数据:是安全稳定的,不需要特别什么处理手段,直接读就可以      *        (2.2)有读有写:2个线程写,8个线程读,如果代码没有特别的处理,那程序肯定崩溃。      *            崩溃原因:写一个数据可能需要十小步,执行到第二步的时候,时间片结束,切换到其他进程读或写,容易造成崩溃。       *            不崩溃处理,读的时候不能写,写的时候不能读。2个线程之间不能同时写,8个线程也不能同时读      *        (2.3)其他案例      *            数据共享:北京-深圳火车T123,10个售票窗口卖票,1,2 窗口同时要订99号座      *    (3)共享数据的保护案例代码(13-46行),(99-103)行      *        网络游戏服务器,两个自己创建的线程,一个线程收集玩家命令(用一个数字代表玩家发的命令),并把命令数据写到一个队列中      *                                            另外一个线程从队列中取出玩发送来的命令。解析,执行玩家需要的动作。      *        用list,list和vector类似,vector:频繁的按顺序插入和删除数据时候效率高。list对于随机的插入和删除效率高。      *                                  vector:支持随机访问。list:不支持随机访问      *        从类A中可以看到,在两个线程中,如果不对list数据加以保护,使得在一个进程读写时候,另一个进程不允许操作,那么程序就会崩溃。      */        

    /*    (1)创建和等待多个线程,线程入口函数统一使用myprint     *        a):多个线程执行顺序是乱的,跟操作系统内部对线程的运行调度机制有关     *        b):主线程等待所有子线程运行结束,最后主线程结束,推荐用join,更容易写出稳定的程序。 少用detach     *        c):咱们把thread对象放入到容器里管理,看起来像个thread对象数组,这对我们一次创建大量的线程,并对大量线程进行管理很方便。     */     vector<thread> mythreads;     for (int i = 0; i < 10; i++) {         mythreads.push_back(thread(myprint, i ));     }     for (auto iter = mythreads.begin(); iter != mythreads.end();iter++) {         (*iter).join();     }

    /*    (2)数据共享问题             (2.1)有读有写     */     vector<thread> mythreads2;     for (int i = 0; i < 10; i++) {         mythreads2.push_back(thread(myprint2, i));     }     for (auto iter = mythreads2.begin(); iter != mythreads2.end(); iter++) {         (*iter).join();     }     

    //    (3)共享数据的保护案例代码     //准备用成员函数作为线程函数的方法写线程。     //问题:下面这个代码如果执行肯定报错,因为25行和33,34行,在同时读写操作,并且没加保护,程序会崩溃掉     //这个时候就应该在一个进程读或者写的时候,对共享数据锁住,不允许其他进程对其进行读写,谁用,谁锁,什么时候解锁等等。     //共享数据只要不被破坏,程序就不会报异常     //解决:引入一个C++解决多线程保护共享数据问题的第一个概念“互斥量”                  A myobj;     std::thread mytobj(&A::inMsgRecvQueue, &myobj);//第二个参数是引用,才能保证线程里用的是同一个对象。     std::thread mytobj2(&A::outMsgRecvQueue, &myobj);     mytobj.join();     mytobj2.join();

    return 0;

}

最新回复(0)