#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;
}