一、创建和等待多个线程二、数据共享问题分析
1.只读的数据2.只写的数据3.其他案例 三、共享数据的保护案例代码
一、创建和等待多个线程
#include二、数据共享问题分析 1.只读的数据#include #include using namespace std; //线程入口函数 void myprint(int inum) { cout << "myprint线程开始执行了,线程编号 = " << inum << endl; //干各种事情 cout << "myprint线程执行结束了,线程编号 = " << inum << endl; } int main() { vector mythreads; //创建10个线程,线程入口函数统一使用 myprint for (int i = 0; i < 10; i++) { //创建10个线程,同时这10个线程已经开始执行 //多个线程执行顺序是乱的,和操作系统内部对线程的运行调度机制有关 //主线程等待所有子线程运行结束,最后主线程结束,推荐join的写法,更容易写出稳定的代码 mythreads.push_back(thread(myprint, i)); } //把thread对象放入容器中进行管理,比较方便 //使用迭代器取出每一个线程 for (auto iter = mythreads.begin(); iter != mythreads.end(); ++iter) { //等待10个线程都返回 iter->join(); } cout << "I love chain !" << endl; return 0; }
只读数据是安全稳定的,只需要读就可以,不需要特别的处理
#include2.只写的数据#include #include using namespace std; vector e_v = { 1,2,3 }; // 共享数据 //线程入口函数 void myprint(int inum) { cout << "id 为" << std::this_thread::get_id() << "的线程 打印 g_v 的值" << e_v[0] << e_v[1] << e_v[2] << endl; } int main() { vector mythreads; //创建10个线程,线程入口函数统一使用 myprint for (int i = 0; i < 10; i++) { mythreads.push_back(thread(myprint, i)); } for (auto iter = mythreads.begin(); iter != mythreads.end(); ++iter) { iter->join(); } cout << "I love chain !" << endl; return 0; }
创建10个线程,2个线程写数据,8个线程读数据,如果没有特别的处理,程序肯定崩溃最简单的不崩溃处理,读的时候不能写,写的时候不能读2个线程不能同时写,8个线程也不能同时读假如写分为10小步,由于任务切换,导致各种诡异的事情发生一个写动作需要一次性被完成,不能被打断 3.其他案例
案例:北京—> 深圳火车,10个售票窗口,1和2号窗口同时要定 99 号坐;
分两步:查看该座位是否被预定,没有预定则预定,预定了则返回已预定
三、共享数据的保护案例代码
这段代码还有问题:共享数据读写矛盾解决方法:因为一个概念 “互斥量”
#include#include #include using namespace std; //成员函数作为线程函数的方法来写线程 class A { public: //线程一:从玩家收到的消息入到一个队列的线程 void inMsgRecvQueue() { for (int i = 0; i < 100000; ++i) { cout << "inMsgRecvQueue()执行,插入一个元素" << i << endl; msgRecvQueue.push_back(i); } } //线程二:把数据从消息队列取出的线程 void outMsgRecvQueue() { for (int i = 0; i < 100000; ++i) { if (!msgRecvQueue.empty()) { //返回第一个元素,但不检查元素是否存在 int command = msgRecvQueue.front(); //移除第一个元素,但不返回 msgRecvQueue.pop_front(); //考虑处理数据...... } else { cout << "outMsgRecvQueue()执行,但目前消息队列为空" << i << endl; } } } private: //容器。专用于代表玩家发送过来的命令 list
msgRecvQueue; }; int main() { //数据共享:网络游戏服务器 //有两个自己创建的线程 //一个线程:收集玩家发来的命令(简化问题:用一个数字代表),将命令数据写入一个队列 //一个线程:从队列中取出玩家发送来的命令,解析,执行玩家要干的动作 //使用list:容器(和vector内部的实现手法是不一样的) //频繁的按照顺序插入和删除数据时list效率高 //对于随意插入和删除数据时vector效率高 A myobja; //第二个参数时引用,才能保证线程里,用的时同一个对象 thread myOutMsgobj(&A::outMsgRecvQueue, &myobja); thread myInMsgobj(&A::inMsgRecvQueue, &myobja); myOutMsgobj.join(); myInMsgobj.join(); return 0; }



