C++11的多线程并发编程(三)

C++11的多线程并发编程(三)

疫情确诊加疑似都快7w+了,能做的也只能在家大门不出,二门不迈了,写一篇继续记录c++11的多线程并发编程

  1. 临时对象在线程中调用的问题
    在创建的子线程中,调用类的对象时考虑到在主线程定义参数执行带参构造函数时,子线程detach时,主线程线执行完清除变量,那么一般在创建主线程时直接构造对象,并在输入函数出增加引用。这样就可以保证,对象带参构造执行于主线程,举个例子:
#include <iostream>
#include <thread>

using namespace std;
class A
{
public:
	int i;
	A(int a):i(a){cout << "createFunction is running"<<"thread id is:"<< this_thread::get_id() << endl;}
	A(const A &a):i(a.i){cout << "copyFunction is running" <<"thread id is:" <<this_thread::get_id() << endl;}
	~A(){cout << "cancelFunction is running" << "thread id is" << this_thread::get_id() << endl;}
};

void myFunc(const A &a)
{
	cout <<"parameter is :"<< a.i << endl;
}

int main()
{
	cout <<"the main thread id is:"<< this_thread::get_id() << endl;
	int par = 99;
	thread mythread(myFunc, A(par));
	
	mythread.detach();
	return 0;
	
}

在这里插入图片描述
可以看到带参构造函数执行于主线程。因此,如果在创建线程的时候传递简单类型参数,例如,int,那么就直接值传递;如果是传递类对象,就像上例,建议都在创建线程的时候构建出临时对象来,然后在调用函数入口处,用引用参数接。
例如,当我们要调用函数对类的成员进行改动,那么就会出现这样的问题:

#include <iostream>
#include <thread>

using namespace std;
class A
{
public:
	mutable	int i;
	A(int a):i(a){cout << "createFunction is running"<<"thread id is:"<< this_thread::get_id() << endl;}
	A(const A &a):i(a.i){cout << "copyFunction is running" <<"thread id is:" <<this_thread::get_id() << endl;}
	~A(){cout << "cancelFunction is running" << "thread id is" << this_thread::get_id() << endl;}
};

void myFunc(const A &a)
{
	a.i = 100;
	cout <<this_thread::get_id()<<"thread's parameter is :"<< a.i << endl;
}

int main()
{
	cout <<"the main thread id is:"<< this_thread::get_id() << endl;
	int par = 99;
	A a(par);
	thread mythread(myFunc, a);
	
	mythread.join();
		cout <<this_thread::get_id()<< "thread's paramter is : "<<a.i << endl;
	return 0;
	
}

我们预期的情况,我在调用函数,参数为引用对象,那么这个a.i的值应该就是100,但是会有两个线程两个不同的成员值,因此,证明了之前讲的,他还是进行了拷贝构造函数,新的对象的成员值了
在这里插入图片描述
解决办法只要在创建输入参数的时候加上ref();就可以出现同一个对象
在这里插入图片描述
在这里插入图片描述

  1. 传参为智能指针以及类成员函数
    这个举个例子,演示当创建线程的时候,智能指针和类成员函数为参数的时候,执行情况:
#include<iostream>
#include<thread>

using namespace std;

class A
{
public:
	int myNum;
	A(int num):myNum(num)
	{
		cout << "createFunction is running" << num << endl;
	}
	A(const A &a):myNum(a.myNum)
	{
		cout << "copyFunction is running" << endl;
	}
	
	void myFunction(int num)
	{
		myNum = num;
		cout << "memberFunction is running" <<myNum <<endl;
	}

	~A()
	{	
		cout << "cancelFunction is running" << endl;
	}
};
void myFunc(unique_ptr<int> ptr)
{
	cout << "ptr point to :" << *ptr << endl;
	return;
}

int main(int argc, char* argv[])
{
	unique_ptr<int> ptrq(new int(100));
	thread mythread1(myFunc, move(ptrq));
	
	A a(999);
	thread mythread2(&A::myFunction, a, 99);
	
	mythread1.join();
	mythread2.join();
	
	cout << "the main thread is end" << endl;
	return 0;
}

在这里插入图片描述
通过运行结果可以看到,两个线程同步运行,会出现交叉情况,main线程是最后结束,成员函数运行成功,且智能指针指向的也传递成功,当指针move操作之后,ptr已经失效了,访问则会报错;

  1. 多线程问题

这里举个多线程针对全局数据的访问案例:

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

using namespace std;

vector<int> parameter = {1,2,3};

void myFunc(int num)
{
	cout << num << "+" << parameter[0] << parameter[1] << parameter[2] << endl;
	return;
}

int main()
{
	vector<thread> vecThread;
	for(int i = 0; i < 10; i++)
	{
		vecThread.push_back(thread(myFunc, i));
	}
	
	for(auto iter = vecThread.begin(); iter != vecThread.end(); iter++)
	{
		iter->join();
	}
	
	cout << "main thread is end;" << endl;
	
	return 0;
	
}

在这里插入图片描述
运行结果显示,当多个线程共同读取全局变量时,能够有效的进行,
上面这个例子,是针对只读数据,是安全的,不需要其他处理,但是如果我一个线程要读,而另外一个线程要写同一个数据,那么会出现什么情况,在操作系统切换的过程中坑定会崩溃,借鉴个案例:
一个车票窗口有两个线程,一个接受乘客排队的购买指令,另一个负责输出乘客指令进行分析指令进行处理,那么根据排队顺序来,需要一个队列来从尾部存储指令,然后从头部输出指令,因此以备两个进程进行读写。

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

using namespace std;

class A
{
public:
	void inCommand()
	{
		for(int i = 0; i < 1000; i++)
		{
			ticket.push_back(i);
			cout << "a command is comming" << endl;
		}
	}
	
	void outCommand()
	{
		for(int j = 0; j < 1000; j++)
		{
			if(!ticket.empty())
			{
				int command = ticket.front();
				ticket.pop_front();	
				cout << "command is :" << command << endl;
			}
			else
			{
				cout << "there is no people" << endl;	
			}
		}
		
	}
	
private:
	list<int> ticket;
};

int main(int argc, char *argv[])
{
	A a;
	thread thread1(&A::inCommand, &a);
	thread thread2(&A::outCommand, &a);
	thread1.join();
	thread2.join();

	cout << "the main thread is end;" << endl;
	return 0;
}

当运行的时候,什么情况都有,有按顺序来的,有一直都显示没有人,然后全是人排队,因此,下一个开始记录,如何互斥的访问这个list

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值