C++多线程 创建线程join、detach、joinable和this_thread和线程排序



join()

  • 进程是资源分配的最小单位
  • 线程共享进程的栈空间,但是每个线程拥有独立的栈
  • 主程序调用join目的是
    等待子线程退出,回收他的资源
    如果子线程已经推出,join、立即执行
    如果没有退出,join阻塞,直到子线程退出
    注意
    不能同时对一个线程使用join和detach
  • 格式
thread my(show);
my.join();

detach()

  • 主程序调用detach目的:
    分离子线程,
    子线程退出时系统才自动回收资源
  • 注意
    不能同时对一个线程使用join和detach
  • 另外可以通过延迟[sleep]主程序return
    来查看detach执行情况
    如果不sleep可能看不到结果,
    但是不影响程序后台执行
    在这里插入图片描述
    在这里插入图片描述

joinable()

bool类型函数,它会表示当前的线程是否是可执行线程(能被join或者detach)
1 -> 表示可以join或者detach
0 ->表示已经可以join或者detach不可再重复回收资源
在这里插入图片描述
在这里插入图片描述

this_thread全局函数

this_thread::get_id()

获取线程ID

void fun(int ret, const string & str) {
		cout << "我是第" << ret << "个成员,我的线程ID是: ";
		cout << this_thread::get_id() << endl;
}
int main() {
		thread my(fun, 10, "哈啊哈哈");
		my.join();
		thread my1(fun, 11, "wssdasda哈");
		cout << "我是主线程,我操作的my1的子线程ID是:" << my1.get_id() << endl;
		my1.join();
		cout << "我是主线程,我操作的my1的子线程ID是:" << my1.get_id();
	}

第二次my1的线程id是0是因为他已经被回收

在这里插入图片描述

this_thread::sleep_for()

线程休眠
时间参数是休眠的具体时间

//方法1
chrono::milliseconds dura(1000);
this_thread::sleep_for(dura);
//方法2
this_thread::sleep_for(chrono::milliseconds(100));
	

this_thread::sleep_until()

时间参数是时间点【略】

this_thread::yield()

让线程放出自己抢到的时间片

swap(不属于this_thread命名空间下)

格式(二者选其一)
swap(a,b);
a.swap(b);

在这里插入图片描述

移动构造函数拷贝进程[不在this::thread]

thread类的拷贝函数被删除
所以用移动构造函数赋值
另外赋值的已经转移,原来的线程付给了新的
原来的废弃,新的接管
如下图my不可再用,my1接管my
使用move可以转为右值在这里插入图片描述
在这里插入图片描述

创建线程

void test01();//函数作为卡调用对象传入
void test02();//类作为可调用对象传入
void test03();//lambda匿名函数

普通函数创建线程

void fun(int ret, const string& str) {
	cout << "我是第" << ret << "个成员,我要说话:“" << str << "”" << endl;
}
int main() {
	thread my(fun, 10, "哈啊哈哈");
	my.join();
}

lambda匿名函数类创建线程

		auto f = [](int ret, const string& str) {
		cout << "我是第" << ret << "个成员,我要说话:“" << str << "”" << endl;
	};
	thread my(f, 10, "哈啊哈哈");
	my.join();
	//注意default和传入值
	thread my1([](int ret = 10, const string &str = "啊啊啊啊啊") {
		cout << "我是第" << ret << "个成员,我要说话:“" << str << "”" << endl;
		},50,"aaaaaa");
	my1.join();

在这里插入图片描述

类创建线程

仿函数创建线程

切记仿函数无参不创建匿名类对象【原因不详】

在这里插入图片描述

#include <iostream>
#include <thread>
using namespace std;
class stu {
public:

	void operator()(int ret, const string& str);
};
void stu::operator()(int ret, const string& str)
{
	cout << "我是第" << ret << "个成员,我要说话:“" << str << "”" << endl;
}
int main() {
	stu s1;
	thread name(s1, 20, "哈哈哈");
	name.join();
	//注意用仿函数类名对象,必须带参数,如果无参只能用上面的不能用stu()
	thread name1(stu(), 30, "aaa");
	name1.join();
}

在这里插入图片描述

类的静态成员函数创建线程

#include <iostream>
#include <thread>
using namespace std;
class stu {
public:

	static void fun(int ret, const string& str);
};
 void stu::fun(int ret, const string& str)//类成员函数类外写
{
	cout << "我是第" << ret << "个成员,我要说话:“" << str << "”" << endl;
}
int main() {
	thread name(stu::fun, 3, "hello");
	name.join();
}

在这里插入图片描述

类的普通成员函数【注意】

①、必须先创建对象
②、对象的生命周期比子线程长
③、注意传进去的是指针
thread name(&stu::fun,&s1, 3, “hello”);

#include <iostream>
#include <thread>
using namespace std;
class stu {
public:
	void fun(int ret, const string& str);
};
 void stu::fun(int ret, const string& str)//类成员函数类外写
{
	cout << "我是第" << ret << "个成员,我要说话:“" << str << "”" << endl;
}
int main() {
	stu s1;
	thread name(&stu::fun,&s1, 3, "hello");
	name.join();
}

在这里插入图片描述

【创建线程总结之万变不离其宗】

普通函数lambdastatic类成员函数

thread thread_name(方法,参数1,参数2 , ... ,参数n)

仿函数类

thread thread_name(类对象,参数1,参数2 , ... ,参数n)

注意如果是匿名类对象(stu())则必须有参数,无参的可使用匿名类对象

普通成员函数

thread thread_name(方法,类对象(不可匿名),参数1,参数2 , ... ,参数n)

相关代码

#include <iostream>
using namespace std;
//thread是一个类
#include <thread>//线程头文件linux和win

//show函数
void show(){
cout<<"我是show函数子线程1"<<endl;
cout<<"我是show函数子线程2"<<endl;
cout<<"我是show函数子线程3"<<endl;
cout<<"我是show函数子线程4"<<endl;
cout<<"我是show函数子线程5"<<endl;
}
//stu类
class stu
{
public:
void operator()(){//方函数
cout<<"我是class类子线程1"<<endl;
cout<<"我是class类子线程2"<<endl;
cout<<"我是class类子线程3"<<endl;
cout<<"我是class类子线程4"<<endl;
cout<<"我是class类子线程5"<<endl;
}
};
void test01();//函数作为卡调用对象传入
void test02();//类作为可调用对象传入
void test03();//lambda匿名函数
int main(){
//test01();
//test02();
test03();
cout<<"我是主线程1"<<endl;
cout<<"我是主线程2"<<endl;

return 0;

}
void test03(){
//()无参数可以省略小括号
thread my_xc([](){
cout<<"我是lambda匿名函数子线程1"<<endl;
cout<<"我是lambda匿名函数子线程2"<<endl;
cout<<"我是lambda匿名函数子线程3"<<endl;
cout<<"我是lambda匿名函数子线程4"<<endl;
cout<<"我是lambda匿名函数子线程5"<<endl;
});
my_xc.join();
}
void test02(){
stu s1;
thread my_xc(s1);
//my_xc.join();
//detach个走个的,输出顺序会混乱
my_xc.detach();//注意join后不可以detach,二者只能有一个

}
void test01(){
//子线程也从函数开始执行(初始函数)(初始函数结束则线程结束)
thread my_xc(show);//show[函数是一个可调用对象
//join-->阻塞主线程,让主线程等待子线程执行完毕,会合后一起走
//注释掉join或放到return 0 后面
//报错terminate called without an active exception
//my_xc.join();//主线程被堵住子线程依然可以走

//joinable可判断是否join、detach过
cout<<"是否可以join或detach:"<<my_xc.joinable()<<endl;

//主线程从mian函数开始(一般主线程结束子线程就会被强行结束[detach例外])
//主线程和子线程没关系可以用detach【注意join之后不可再detach】
my_xc.detach();//【守护线程】(子线程在后台运行)【但是不建议用detach】
cout<<"是否可以join或detach:"<<my_xc.joinable()<<endl;
}

使用detach格外小心

传递int类型时不建议用引用(detach)
如果传递类对象要进行转换,不要让编译器进行隐式转换
【使用临时对象可以确保线程参数再mian函数结束之前就被构造出来】
thread my(show1,i,string(buff));
thread my(show1,i,mydelfclass(buff));

#include <iostream>
using namespace std;
//thread是一个类
#include <thread>//线程头文件linux和win

//类
class stu{
public:
int m;
stu(int m):m(m){
cout<<"stu的构造函数id:"<<this_thread::get_id()<<endl;
}
stu(const stu &s){
cout<<"stu的拷贝函数"<<endl;
}
~stu(){
cout<<"stu的西沟函数"<<endl;
}
};

//show函数
void show(const int &i ,const string &mybuff){
cout<<i<<endl;
cout<<mybuff<<endl;
}
//class_show
void show_class(const int &i ,const stu &my_stu){
cout<<&my_stu<<endl;
}


void test01();
void test02();
void test03();
int main(){
//test01();
test02();

cout<<"我是主线程1:"<<this_thread::get_id()<<endl;
cout<<"我是主线程2:"<<this_thread::get_id()<<endl;

return 0;

}

void test02(){
int i = 1;
int arr = 12;

thread my(show_class,i,stu(arr));

my.detach();//但是detach会存在问题【不推荐引用,但是指针一定不可以】
}
void test01(){
int i = 1;
int &arr = i;
char buff[] = "我是子线程";
//string(buff)对这个对象进行转【临时的string对象】
thread my(show,i,string(buff));
//my.join();//show用的是i是thread的拷贝的新地质
my.detach();//但是detach会存在问题【不推荐引用,但是指针一定不可以】
}


在这里插入图片描述

趣味练习 之 线程排序

sleep排序法

#include <iostream>
#include <thread>
#include <windows.h>
#include <mutex>
#include <vector>
#include <future>
using namespace std;
vector <double> res;
mutex flag;
void show(const double ret) {
	Sleep(ret*1000);//排序的数字越细,*的数字要越大
	flag.lock();
	res.push_back(ret);
	cout << "我是" << ret << "我排序完毕" << endl;
	//cout << "我的线程ID:" << this_thread::get_id() << endl;
	flag.unlock();
}

int main() {
	vector <double>ret = { 10,8,20,11,21,21.001};
	thread n1(show, ret[0]);
	thread n2(show, ret[1]);
	thread n3(show, ret[2]);
	thread n4(show, ret[3]);
	thread n5(show, ret[4]);
	thread n6(show, ret[5]);
	n1.join();
	n2.join();
	n3.join();
	n4.join();
	n5.join();
	n6.join();
	for (auto a : res)
		cout << a << endl;
}

在这里插入图片描述

猴子排序法

#include <iostream>
#include <thread>
#include <windows.h>
#include <mutex>
#include <vector>
#include <future>
using namespace std;
vector <double> res;
mutex flag;
void show(const double ret) {
	flag.lock();
	res.push_back(ret);
	cout << "我是:" << ret << endl;
	flag.unlock();
}

int main() {
	bool flag = 0;
	a:
	vector <double>ret = { 10,8,20,11,21,21.001};
	thread n1(show, ret[0]);
	thread n2(show, ret[1]);
	thread n3(show, ret[2]);
	thread n4(show, ret[3]);
	thread n5(show, ret[4]);
	thread n6(show, ret[5]);
	n1.join();
	n2.join();
	n3.join();
	n4.join();
	n5.join();
	n6.join();
	for (int i = 0; i < res.size()-1; i++)
	{
		if (res[i] <= res[i + 1])
			flag = 1;
		else {
			flag = 0;
			res.clear();
			cout << "排序不对,再进行新一轮排序" << endl;
			goto a;
		}
	}
//	if (flag == 1)
	cout << "排序完毕"<<endl;
		for (auto a : res)
			cout << a << endl;
}

在这里插入图片描述

  • 4
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
C++中使用多线程可以通过使用`<thread>`头文件中的`std::thread`类来实现。以下是几个使用C++多线程的例子: 范例1: ```cpp #include <iostream> #include <thread> using namespace std; void myPrint() { cout << "我的线程开始运行" << endl; //... cout << "我的线程运行完毕" << endl; } int main() { thread myThread(myPrint); myThread.join(); cout << "Hello World!" << endl; system("pause"); return 0; } ``` 上述代码中,我们使用`std::thread`类创建了一个线程对象`myThread`,并指定了线程执行的起点为`myPrint`函数。然后我们调用`myThread.join()`函数阻塞主线程,等待子线程完成执行,然后主线程继续执行。 范例2: ```cpp #include <iostream> #include <thread> using namespace std; class Ta { public: void operator()() { cout << "我的线程开始运行" << endl; //... cout << "我的线程运行完毕" << endl; } }; int main() { Ta ta; thread myThread(ta); myThread.join(); cout << "Hello World!" << endl; system("pause"); return 0; } ``` 上述代码中,我们定义了一个类`Ta`,重载了`operator()`运算符,然后将对象`ta`传给`std::thread`类的构造函数创建了一个线程对象`myThread`,线程执行的起点为`ta`对象。然后我们调用`myThread.join()`函数阻塞主线程,等待子线程完成执行,然后主线程继续执行。 范例3: ```cpp #include <iostream> #include <thread> using namespace std; void myPrint() { cout << "我的线程开始运行" << endl; //... cout << "我的线程运行完毕" << endl; } int main() { thread myThread(myPrint); myThread.join(); if (myThread.joinable()) { cout << "可以调用join()或者detach()" << endl; } else { cout << "不能调用join()或者detach()" << endl; } cout << "Hello World!" << endl; system("pause"); return 0; } ``` 上述代码中,我们创建了一个线程对象`myThread`,线程执行的起点是函数`myPrint`。然后我们调用`myThread.join()`函数阻塞主线程,等待子线程完成执行,然后主线程继续执行。在之后,我们使用`myThread.joinable()`函数来判断线程是否可以调用`join()`或者`detach()`函数。 以上是使用C++实现多线程的几个范例。希望对您有所帮助。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* *3* [Windows环境下的多线程编程(上)C++](https://blog.csdn.net/m0_56574701/article/details/124174550)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 100%"] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值