一、创建多个子线程
前面三章讲的例子都是只有一个子线程和主线程,然而实际中有多个子线程。那么下面介绍如何创建多个子线程。
1 #include <iostream> 2 #include <vector> 3 #include <list> 4 #include <thread> 5 using namespace std; 6 7 void mythread(int i) 8 { 9 cout << "id为" << std::this_thread::get_id() << "的线程" << endl; 10 cout << "i=" << i << endl; 11 return; 12 } 13 14 int main() 15 { 16 vector<thread> mythreads; 17 for (int i = 0; i < 10; i++) 18 { 19 mythreads.push_back(thread(mythread, i)); //创建是10个线程并放入容器中 20 } 21 for (auto ite = mythreads.begin(); ite != mythreads.end(); ++ite) 22 { 23 ite->join(); //主线程等待10个线程执行完 24 } 25 cout << "主线程执行完毕" << endl; 26 system("pause"); 27 return 0; 28 }
运行结果
可以看出,虽然所有子线程执行完了才到主线程,但各个子线程的执行期间是乱的,没有谁等谁。那么就会引发一个数据共享的问题。
二、数据共享问题
如果多个线程之间知识单纯的读取数据,那么程序是不会出现奔溃等严重问题的,是安全稳定的。但如果既读数据又写数据,程序很有可能崩溃。比如有5个线程,2个线程写数据,3个线程读取同样的数据,试想如果写数据的线程还没写入数据,其他线程就进行读数据操作了,那么必然会出现问题。下面举一个例子说明。
1 #include <iostream> 2 #include <vector> 3 #include <list> 4 #include <thread> 5 using namespace std; 6 //队列,先进先出 7 class A 8 { 9 private: 10 list<int> msg; 11 public: 12 //把数据写入队列 13 void inMsgRecv() 14 { 15 for (int i = 0; i < 10000; i++) 16 { 17 cout << "插入一个元素" << i << endl; 18 msg.push_back(i); 19 } 20 } 21 //从队列读数据 22 void outMsgRecv() 23 { 24 for (int i = 0; i < 10000; i++) 25 { 26 if (!msg.empty()) 27 { 28 int GetMsg = msg.front(); //接受消息队列的首部 29 msg.pop_front(); //移除首部 30 //....然后可以对GetMsg进行你想要的操作 31 //cout << "GetMsg:" << GetMsg << endl; 32 } 33 else 34 { 35 cout << "没有数据可读" << endl; 36 } 37 } 38 } 39 }; 40 41 int main() 42 { 43 A myobj; 44 //以成员函数作为线程函数,第一个&是取地址,第二个&是引用 45 thread mythread1(&A::inMsgRecv, &myobj); 46 thread mythread2(&A::outMsgRecv, &myobj); 47 mythread1.join(); 48 mythread2.join(); 49 system("pause"); 50 return 0; 51 }
运行结果
那么要处理多线程的数据共享问题,就要涉及一个概念“互斥量”,下面一章将会讲到。