C++多线程编程(1):线程的创建方式

文章首发于我的个人博客:欢迎大佬们来逛逛

进行与线程

多线程是指多个线程并发执行的过程。

进程与线程的关系:

  • 进程是一个独立运行的应用程序
  • 线程是指进程内独立执行的一个单元,一个进程中可能有多个线程。

C++中如何实现多线程

使用 #include <thread> 头文件,里面定义了很多的线程函数。

其中,使用 thread 创建一个线程.

比如我有两个函数,分别是:

  • print1是主线程。
  • 下面四个函数分别是子线程。
void print1() {
	std::cout << "主线程\n";
}
void printtttt1() {
	Sleep(2000);
	std::cout << "子线程1\n";
}
void printtttt2() {
	Sleep(2000);
	std::cout << "子线程2\n";
}
void printtttt3() {
	Sleep(2000);
	std::cout << "子线程3\n";
}

现在我们想让他们四个同时执行?如何操作。

  1. 首先来创建线程对象:

thread 用作线程对象类型,然后传递一个函数指针(以模板形式)给到这个对象,则这个对象就是一个线程对象

我们将这三个子线程分别为三个不同的线程对象。print1为主线程。

std::thread t1(printtttt1);
std::thread t2(printtttt2);
std::thread t3(printtttt3);

创建完成后我们使用 join将子线程添加到主线程中:

t1.join(); 
t2.join();
t3.join();

然后运行,就会发现,三个子线程和主线程同时结束,说明多线程有效。

int main() {
	std::thread t1(printtttt1);
	std::thread t2(printtttt2);
	std::thread t3(printtttt3);
	//t.join(); //子线程加入主线程
	//detach: 子线程和主线程各自玩个的,等待主线程执行完毕
	t1.join(); 
	t2.join();
	t3.join();
	print1();
	return 0;
}

观察到细节:

  • 三个子线程都有一个等待两秒的功能,如果不是多线程,则很容易想到单纯的运行这四个函数可能需要6秒多才完成
  • 但是他们四个是同时完成的,即只用了两秒
  • 并且我们没有限制线程之间的执行顺序,因此他们的顺序是任意的。

在这里插入图片描述


join函数就是将子线程加入到主线程,然后和主线程一起执行完毕。

还有个 detach函数:

  • detach: 子线程和主线程各玩各的的,等待主线程执行完毕则停止。
t1.detach();
t2.detach();
t3.detach();
print1();

则会出现什么?

  • 程序立刻结束,我管你子线程执行了没有,只要我的主线程结束了,则程序就结束。 因此程序直接执行主线程函数,而不会执行三个子线程。

在这里插入图片描述


joinable:对线程是否可以join和detach操作进行判断。即一个线程只能进行一次join或者detach操作,如果你写了很多的代码,明明已经join过一次了,但是忘记了,因此又join了一次,这时就会 报错!!!

该函数在可以 join 或 detach 的时候返回true,否则返回false。

因此常见的可以避免错误的方式:

if (t1.joinable()) {
		t1.join(); //t1.detach()
	}

创建线程的多种方式

thread类型的构造函数是怎样的呢? 它可以构造什么样的线程函数对象呢?

template <class _Fn, class... _Args,   .......... >
explicit thread(_Fn&& _Fx, _Args&&... _Ax) {
        _Start(_STD forward<_Fn>(_Fx), _STD forward<_Args>(_Ax)...);
}
  • Fn:接受一个函数指针。
  • Args:接受函数的参数。

无参函数

这是最简单的创建线程的方式:

// 1. 传递无参void函数
void print() {
	std::cout << "子线程: " << "传递无参void函数\n";
}
void create1() {
	std::thread t1(print);
	t1.join(); //加入主线程
}

lambda表达式

// 2. 传递lambda表达式
void create2() {
	std::thread t1([]() {
		std::cout << "lambda表达式\n";
		});

	if (t1.joinable()) {
		t1.join();
	}
}

常成员函数

  • 普通内置类型:int
  • 常引用:const string& ; const int&
  • 常指针:const int*
  • 都可以直接传递
// 3. 传递有参函数
// 3.1  普通参数
void print2(int num, const std::string& name, const int age, const int& yina, const int* cp) {
	std::cout << "num: " << num << " name: " << name << " age: " << age << " yina: "
		<< yina << " cp: " << *cp << '\n';
}
void create3() {
	int num = 10, age = 20, yina = 999, cpnum = 50;
	std::thread t1(print2, num, "你好", age, yina, &cpnum);
	if (t1.joinable()) {
		t1.join();
	}
}

not常成员引用函数

  • not常引用: 如果是**不带const**的引用类型,则必须使用 std::ref 修饰,否则会报错:
  • not常指针:不会报错。
// 必须加以 ref 修饰;否则就传递const的引用
void print3(int& num) {
	std::cout << "引用 num: " << num << '\n';
}
void create4() {
	int num = 10;
	std::thread t1(print3, std::ref(num));
	if (t1.joinable()) {
		t1.join();
	}
}

//不会报错,const和非const的指针都不会报错,传递地址即可
void print4(int* num) {
	std::cout << "指针 num: " << *num << '\n';
}
void create5() {
	int num = 10;
	std::thread t1(print4, &num);
	if (t1.joinable()) {
		t1.join();
	}
}

智能指针

传递智能指针 unique_ptr 需要加 move移动,因为unique_ptr只允许存在一份,但是移动后本地将消失。

void print5(std::unique_ptr<int> ptr) {
	std::cout << "智能指针: " << *ptr.get() << '\n';
}
void create6() {
	std::unique_ptr<int> pointer(new int{ 100 });
	std::thread t1(print5, std::move(pointer));
	if (t1.joinable()) {
		t1.join();
	}

	//null
	std::cout << "移动之后,智能指针: " << pointer.get() << '\n';
}

仿函数

直接传递即可。

class Foo {
public:
	Foo() {}
	void operator()() {
		std::cout << "仿函数\n";
	}
};
void create7() {
	Foo f = Foo();
	//1. 仿函数对象
	std::thread t1(f);
	if (t1.joinable()) {
		t1.join();
	}

	//2. 匿名函数对象
	std::thread t2((Foo()));
	if (t2.joinable()) {
		t2.join();
	}
}

类的普通成员函数

函数指针的形式,先传递类名所对应的**函数地址,然后再传递类对象**。

class Aoo {
public:
	Aoo() {}
	void test() {
		std::cout << "普通成员函数\n";
	}
};
void create8() {
	Aoo a = Aoo();
	std::thread t1(&Aoo::test,a);
	if (t1.joinable()) {
		t1.join();
	}
}

综合测试

int main() {
	create1();
	create2();
	create3();
	create4();
	create5();
	create6();
	create7();
	create8();
	return 0;
}

在这里插入图片描述


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Yuleo_

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值