创建多个线程及数据共享问题分析

创建多个线程及数据共享问题分析

1.创建和等待多个线程

void myprint(int num)
{
	std::cout << "myprint线程开始执行,线程编号 = " << num << std::endl;

	//其他操作···
	
	std::cout << "myprint线程结束执行,线程编号 = " << num << std::endl;
}

int main()
{
	std::vector<std::thread>mythreads;

	//创建10个线程,线程入口函数都是用myprint
	for (int i = 0; i < 10; i++)
	{
		mythreads.push_back(std::thread(myprint, i));// 创建并执行线程
	}

	for (auto it = mythreads.begin(); it != mythreads.end(); it++)
	{
		it->join();//等待10个线程都返回
	}

	std::cout << "主线程执行完毕." << std::endl;

	getchar();
	return 0;
}

  执行结果:
创建多个线程及数据共享问题分析
  结果分析总结:
  ① 多个线程执行顺序通常是乱的,这跟操作系统内部线程的运行调度机制有关;
  ② 推荐使用join()这样让主线程等待所有子线程运行结束,最后主线程结束,这样程序更稳定。

2.数据共享问题分析

(1)只读的数据

std::vector<int>vec = { 1,2,3 };//共享数据

void myprint(int num)
{
	std::cout << "ID为" << std::this_thread::get_id() << "的线程打印出的vec的值为:" << vec[0] << vec[1] << vec[2] << std::endl;
}

int main()
{
	std::vector<std::thread>mythreads;

	//创建10个线程,线程入口函数都是用myprint
	for (int i = 0; i < 10; i++)
	{
		mythreads.push_back(std::thread(myprint, i));// 创建并执行线程
	}

	for (auto it = mythreads.begin(); it != mythreads.end(); it++)
	{
		it->join();//等待10个线程都返回
	}

	std::cout << "主线程执行完毕." << std::endl;

	getchar();
	return 0;
}

  执行结果:
创建多个线程及数据共享问题分析
  结果分析总结:
  ① 只读数据是安全稳定的,不需要特别的处理手段。

(2)有读有写

  如,2个线程写,8个线程读,若果代码特别处理,程序必然崩溃。
  最简单的处理手段:读的时候不能写,写的时候不能读。即,2个线程不能同时写,8个线程不能同时读。

3.共享数据的保护案例

  网络游戏服务器,创建两个线程,其中一个线程收集玩家命令(用一个数字代表玩家发送的命令),并把命令写到队列中;另外一个线程,从队列中取出玩家发送来的命令并解析,然后执行玩家需要的动作。

#include<iostream>
#include<vector>
#include<list>
#include<thread>

class A
{
public:
	//把收到的消息(玩家命令)写入到一个队列的线程
	void inMsgRecvQueue()
	{
		for (int i = 0; i < 100000; ++i)
		{
			std::cout << "inMsgRecvQueue()执行,插入一个元素" << i << std::endl;
			msgRecvQueue.push_back(i);//假设数字i就是收到的命令
		}
	}

	//把收据从消息队列中取出的线程
	void outMsgRecvQueue()
	{
		for (int i = 0; i < 100000; ++i)
		{
			if (!msgRecvQueue.empty())
			{
				int command = msgRecvQueue.front();
				msgRecvQueue.pop_front();//移除list首元素
			}
			else
			{
				std::cout << "outMsgRecvQueue()执行,但目前消息队列中为空" << std::endl;
			}
		}
		std::cout << "END" << std::endl;
	}

private:
	std::list<int>msgRecvQueue;//存储玩家发送过来的命令--消息队列
};

int main()
{
	A myobj;
	std::thread m_outMsgThread(&A::outMsgRecvQueue, &myobj);
	std::thread m_inMsgThread(&A::inMsgRecvQueue, &myobj);
	m_outMsgThread.join();
	m_inMsgThread.join();

	getchar();
	return 0;
}

  因为没有控制读写,所以执行出现问题:
创建多个线程及数据共享问题分析
  解决方法在下一节解决多线程保护共享数问题---互斥量