使用入口函数创建多个线程

2023-05-16

 

 

#include <iostream>
#include <thread>

using namespace std;
void func(int a,int b)
{
	cout<<a+b
	<<this_thread::get_id()
	<<endl;
}

int mian()
{
	thread th =thread(func, 2 ,3)//使用函数指针来起一个线程
	th.detach();
	if(th.joinable())
	{
	    th.join();
	}
	cout<<this_thread::get_id()<<endl;
}

几种方式创建线程的区别!

1.4总结线程:
a)线程是用来执行代码的;
b)把线程这个东西理解成一条代码执行通路,一个新线程代表一条新的通路。
c)一个进程自动包含一个主线程,主线程随着进程默默启动并运行,我们可以通过编码来创建多个其他线程(非主线程)
但是创建的数量最大都不建议超过200~ 300个,至于到底多少个适合,大家在实际项目戏中科院不断调整和优化,有的时候
d)因为主线程是自动启动的,所以一个进程中最少有一个线程(主线程)。
e)多线程程序可以同时干多个事,所以运行效率高。但是到底有多高,并不是一个很容易评估和量化的东西。
大家任然需要在实际编程和项目中体会和优化;

1.5学习心得:
开发多线程程序:是商用的必须需求;
线程开发有一定难度,实现代码也复杂,理解上更难一些,需要一定的学习时间。

c++线程会涉及很多新概念,对于c++道路成长特别关键,不要急于求成。


二、并发的实现方法

两个或者更多的任务(独立的活动)同时发生(进行):一个程序同时执行多个独立的任务。
实现的手段:
a)我们通过多个进程实现并发
b)在单独的进程中,创建多个线程来实现并发,自己写代码来创建主线程之外的线程。

2.1)多进程并发
word 启动后就是进程
账号服务器、游戏逻辑服务器。服务器进程之间的通信。
进程间的通信(同一个电脑上:管道,文件,消息队列,共享内存);          进程间数据保护机制?
不同电脑上:socket通信技术

2.2)多进程并发:单个进程中,创建了多个线程。
线程:感觉像轻量级的进程,每个线程都有自己独立的运行路经,但是一个进程中的所有线程共享地址空间(共享内存)
全局变量,指针,引用,都可以在线程之间传递,所以使用多线程开销远远小于多进程。
共享内存带来新问题:数据一致性的问题:线程A,线程B不能同时写操作;

多进程并发和多线程并发,虽然可以混合使用,但是老师建议,优先考虑多线程技术

在本章中,只讲解多线程并发的开发技术,后续谈到并发,都指多线程并发。
2.3总结
线程的优点:
1)线程启动速度更快,更轻量级。
2)系统资源开销更少,执行速度更快,比如共享内存这种通信方式比任何其他的通信方式都快。
缺点:
1)使用有一定难度,要小心处理数据的一致性问题。

三:c++11新标准线程库
以往: windows :CreateThread() ,_beginthread(),_beginthreadxe()创建线程
Linux环境下:pthread_create()创建线程
临界区,互斥量;
以往多线程代码不能跨平台;
POSIX thread(pthread):跨平台;每一个平台需要做一些配置,用起来并不方便

c++11增加对多线程的支持,意味着可移植性(跨平台);


主线程从main()开始执行,那么我们自己创建的线程,也需要从一个函数开始运行(初始函数),一旦这个函数运行完毕,这个线程也就结束了
整个进程是否执行完毕的标志是,主线程是否执行完,如果主线程执行完毕了,就代表整个进程执行完毕了。
此时如果其他子线程还没有执行完毕,但是主线程执行完了,一般情况下,这些子线程,也会被操作系统强制终止

如果想保持子线程(自己用代码创建的线程)的运行状态,那么就要让主线程一直保持运行,
这边也有例外。
a)包含一个include<thread>头文件
b)创建的函数
c)main中开始写代码
这个代码有两个线程在跑,相当于这个程序的执行有两条线同时运行,即使一条线堵住了,另一条线依然可以执行。
thread 是标准库里面的类
jion():加入/汇合,说白了就是阻塞主线程,让主线程等待子线程执行完毕,然后子线程与主线程汇合,然后主线程再往下走。
detach():一般情况下,多线程程序要等待子线程执行完毕,然后再自己执行退出。
detach(),分离,也就是主线程不和子线程汇合了,主线程执行你的,子线程执行我的,主线程不必等待子线程的汇合了,可以执行完毕。
为什么引入这个detach(),我们创建了很多子线程,让主线程逐个等待子线程结束,这种编程方法不好,所以加入了detach() 
一旦detach()后,与主线程相关的thread对象就会失去与主线程的关联,此时子线程,就会驻留在后台运行,主线程与子线程失去联系。
这个子线程就c++运行时库接管了,当这个子线程执行完后,有运行时库负责清理线程相关的资源(守护线程)
joinable():判断是否可以成功使用jion()或detach()返回true,否则返回false
@@@join 后就不能再次join或者detach,同样detach后就不能再detach或者jion

如果主线程执行完毕,但是子线程没执行完,这种程序员不合格,程序也是不稳定的。
一个良好的程序,应该是主线程等待子线程执行完毕,

#include <iostream>
#include <thread>

using namespace std;

void print()
{
	cout<<"我的线程开始了"<endl;
	//...........
	cout<<"我的线程结束了"<endl;
}
int mian()
{
	thread th =thread(print)//使用函数指针来起一个线程,print线程执行入口,print线程开始执行
	if(th.joinable())
	{
		cout<<"joinable() == true"<<endl;
		th.jion();在这里写会比较安全
		//th.detach();//join 后就不能再次join或者detach,同样detach后就不能再detach或者jion
	}
	else
	{
		cout<<"joinable() == false"<<endl;
	}
	//th.jion();//主线程阻塞,等待子线程th执行完,再继续执行
	
	//th.detach();
	//主线程与子线程分离,会使print线程失去我们的控制。如果主线程与子线程干的活没有什么关系,是可以使用detach的
	//一旦使用了th.detach(),就不能join()回来了,否则系统会有异常
	if(th.joinable())
	{
		cout<<"joinable() == true2"<<endl;
	}
	else
	{
		cout<<"joinable() == false2"<<endl;
	}
	cout<<"主线程收尾,正常退出"<endl;
	return 0;
}





class TA
{
	public:
	int &m_i;
	TA (int &i):m_i(i)
	{
		cout<<"构造函数被执行"<<endl;
		
	}
	TA(const TA &ta)m_i(ta.m_i)
	{
		cout<<"拷贝构造函数被执行"<<endl;
		
	}
	~TA()
	{
		cout<<"析构构造函数被执行"<<endl;
	}
	void operator()()//不能带参数
	{
		cout<<"我的线程开始了"<endl;
	    //...........
	    cout<<"我的线程结束了"<endl;
		cout<<"m_i的值是"<<m_i<<endl;
	}
	
}


int main()
{
	int a=9;
	TA ta(a);
	thread myth(ta);//ta可调用对象,使用类对象创建线程
	//myth.join();
	myth.detach();一旦调用了这个,主线程一旦结束了,这里的ta对象还在吗?
	//对象不在了,这个对象实际上是负责到线程中去了,执行完线程后,ta会被销毁,但是所复制的对象TA依旧存在
	//所以,只要你这个TA类的对象里没有引用,没有指针,那么就不会产生问题。
	
	
	
	auto mylamthread=[]//yong lambda表达式创建线程
	{
		cout<<"thread start"<<endl;
		cout<<"thread start"<<endl;
		
		cout<<"thread start"<<endl;
	};
	thread mythread2(mylamthread);
	mythread2.detach();
	cout<<"主线程收尾,正常退出"<endl;
	return 0;
}




void print(const int &i,char *pbuf)
//创建线程的参数,绝对不推荐使用引用,也不能使用指针,因为当线程detach后,主线程结束后,主线程中原来的引用变量和指针会被销毁
{
	cout<<i<<endl;
	cout<<pbuf<<endl;
	
}

int main()
{
	//传递临时对象作为线程参数
	//陷阱1
	int mvar =1;
	int &mv=mvar;
	char mybuf[]="this is test1"
	thread myth1(print,mvar,mybuf);
	thread myth1(print,mvar,string(mybuf));
	myth1.join();
	myth1.detach();
	cout<<"主线程收尾,正常退出"<endl;
	return 0;
}

类对象用作函数形参,会调用拷贝构造函数

 

 

 

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

使用入口函数创建多个线程 的相关文章

随机推荐