c++ 11 thread使用

c++11推出的封装类,网上说法褒贬不一,有说让线程简单很多的,而且跨平台的,也有说这个写的很多功能不该做,或者该有的功能没写
linux底下编程可能会更推荐用Pthreads ?或者两个结合一起使用
反正刚转语言,啥都不懂,都研究一下。。

1.调用类内方法,带参数及不带参数

class ThreadTest {
public:
	static void f1() {
		int cnt = 5;
		while (--cnt > 0)
		{
			cout << " Calling Function f1 " << endl;
			Sleep(1000);
		}
	};
	static void f2(int& input) {
		int cnt = 5;
		while (cnt-- > 0)
		{
			cout << " Calling Function f2 input:" << input << endl;
			Sleep(1000);
		}
	};
	void test1() {
		thread t1(f1);//f1:类内静态方法
		int input = 2;
		thread t2(f2, ref(input));//f2:类内静态带参方法
		t1.join();
		t2.join();
	}
}

2.调用类内非静态方法:传入实例及通过类名引用

class ThreadTest {
public:
	void f3() {
		cout << "Calling Function this::f3 " << endl;
	};
	void f4(int input) {
		cout << "Calling Function this::f4 , input :" << input << endl;
	};
	void test1() {
		thread t3(&ThreadText::f3, this);
		thread t4(&ThreadText::f4, this, 4);
		t3.join();
		t4.join();
	}
}

3.通过lambda调用匿名函数,或在匿名函数中调用其他函数
[]内捕捉的变量是非静态的,(静态且访问级别足够的不需要捕捉)

class ThreadTest {
public:
	void f6(int input) {
		cout << "Calling Function this::f6 , input :" << input << endl;
	};
	void test1() {
		int i = 5;
		thread t5([i] {
			cout << "Calling Function f" << i << " with Lambda" << endl;
			});
		i = 6;
		thread t6([this, i] {
			f6(i);
			});
		t5.join();
		t6.join();		
	}
}

4.detach 和 join:
区别:
join会阻塞当前线程,直至子线程全部完成,当前线程才允许结束
detach则不会,和当前线程没有任何关系独立运行,直至自身结束或程序结束
无论是join 还是detach,调用之后joinable()均为false

class ThreadTest {
public:
	void f7() {
		int Cnt = 500;
		while (--Cnt >= 0) {
			cout << "Calling Function f7 , left Time :" << Cnt << endl;
			Sleep(1000);
		}
	};
	static void f8() {
		int Cnt = 5;
		while (--Cnt >= 0) {
			cout << "Calling Function f8 , left Time :" << Cnt << endl;
			Sleep(1000);
		}
	}
	void test1() {
		thread t7(&ThreadText::f7, this);
		thread t8(&ThreadText::f8);//这样写也是可以的,等价直接写f8
		t7.detach();
		t8.join();
	}
};

结果:t7还没跑完,但是t8先跑完了,test1方法结束,main中调用完之后结束,t7随之也结束了
在这里插入图片描述
关于join的阻塞问题:
示例如下:

class ThreadJoinTest {
public:
	void test() {
		thread t1([] {
			Sleep(5000);
			cout << "t1Function has been Excute" << endl;
			});
		thread t2([] {
			Sleep(3000);
			cout << "t2Function has been Excute" << endl;
			});
		thread t3([] {
			Sleep(1000);
			cout << "t3Function has been Excute" << endl;
			});
		t1.join();
		t2.join();
		t3.detach();
		thread t4([] {
			Sleep(50000);
			cout << "t4Function has been Excute" << endl;
			});
		t4.detach();
		thread t5([] {
			Sleep(1000);
			cout << "t5Function has been Excute" << endl;
			});
		t5.join();
		cout << "test end" << endl;
	}
};

在这里插入图片描述
结论是:join不会阻塞当前线程的其他子线程的实例化或join或detach?
再改一下代码:

class ThreadJoinTest {
public:
	void test() {
		thread t1([] {
			Sleep(5000);
			cout << "t1Function has been Excute" << endl;
			});
		thread t2([] {
			Sleep(3000);
			cout << "t2Function has been Excute" << endl;
			});
		thread t3([] {
			Sleep(1000);
			cout << "t3Function has been Excute" << endl;
			});
		t1.join();
		t2.join();
		t3.detach();
		thread t4([] {
			Sleep(50000);
			cout << "t4Function has been Excute" << endl;
			});
		t4.detach();
		thread t5([] {
			Sleep(10000);
			cout << "t5Function has been Excute" << endl;
			});
		t5.join();
		cout << "do nothing" << endl;
		thread t6([] {
			Sleep(1000);
			cout << "t6Function has been Excute" << endl;
			});
		t6.join();
		cout << "test end" << endl;
	}
};

在这里插入图片描述
t5 join之后等了足足10秒才打印do nothing,即对线程相关的操作是不阻塞的?遇到当前线程的其他操作才会阻塞?

5.condition_variable_any,condition_variable 和 mutex
当存在多个线程,你想将这些线程按照指定的规律执行,可以通过很多方法,比如信号量,互斥锁,条件变量等实现
当不需要按照某些特定顺序时,保持数据的一致性即可时,可以通过互斥锁mutex:

mutex.lock();
mutex.unlock();

当需要按照某些特定顺序,比如leetCode中的FooBar问题等,就需要用到条件变量
另一个情景:当存在5个线程,你想将这五个线程按顺序从10到1的顺序打印,并且是交替打印,即5个线程按顺序打印出10,再按顺序打出9直到1时,就需要条件变量

class ThreadMutexTest {
public:
	int t;
	condition_variable_any  cv;
	/*condition_variable cv;*/
	mutex m;
	ThreadMutexTest() {
		t = 0;
	}
	void fn(int Cnt, int n, int max) {
		while (Cnt > 0)
		{
			
			lock_guard<mutex> locker(m);
			cv.wait(m, [n, this] {return t == n; });
			t = (t + 1) % max;
			cout << "Function f" << n + 1 << " printline Cnt:" << Cnt << endl;
			cv.notify_all();
			Cnt--;
		}
	}
	void test() {
		vector<thread> v;
		for (int i = 0; i < 5; i++)
			v.emplace_back(&ThreadMutexTest::fn, this, 10, i, 5);//转移构造,比push_back少了拷贝,减少开辟临时变量空间
		for_each(v.begin(), v.end(), std::mem_fn(&std::thread::join));

	}
};

结果:
在这里插入图片描述
使用步骤:
声明lock_guard/unique_lock (上锁,等价于mutex.lock() .unlock(),但是更可靠,在一组括号中会自动的调用析构函数确保unlock得到执行,避免使用mutex出现忘记或者异常抛出导致的没有unlock而出现的死锁)
详情直接贴另一位大佬的链接:
C++锁的管理-- std::lock_guard和std::unique_lock

lock_guard<mutex> locker(m);

等待获取锁,wait(锁,lambda表达式),指定获取锁的条件

cv.wait(m, [n, this] {return t == n; });

通知其他等待的线程,让他们来抢锁

cv.notify_all();

上边只用到了condition_variable_any
如果同样的代码,仅将condition_variable_any 改为 condition_variable
则会报错:
在这里插入图片描述改成如下:

class ThreadMutexTest {
public:
	int t;
	condition_variable  cv;
	/*condition_variable_any cv;*/
	mutex m;
	ThreadMutexTest() {
		t = 0;
	}
	void fn(int Cnt, int n, int max) {
		while (Cnt > 0)
		{
			
			unique_lock <mutex> locker(m);
			cv.wait(locker, [n, this] {return t == n; });
			t = (t + 1) % max;
			cout << "Function f" << n + 1 << " printline Cnt:" << Cnt << endl;
			cv.notify_all();
			Cnt--;
		}
	}
	void test() {
		vector<thread> v;
		for (int i = 0; i < 5; i++)
			v.emplace_back(&ThreadMutexTest::fn, this, 10, i, 5);//转移构造,比push_back少了拷贝,减少开辟临时变量空间
		for_each(v.begin(), v.end(), std::mem_fn(&std::thread::join));

	}
};

结果也是一样的,和上一段区别在:
lock_guard变成了unique_lock
cv.wait里从mutex实例 变成了 unique_lock实例
除此之外这两个用法好像差不多
还是直接贴另一个大佬的链接,这边就不过多的介绍了:
C++11并发编程-条件变量(condition_variable)详解

6.其他:
1.Sleep && sleep_until && sleep_for
Sleep(毫秒数,这个就不提了)

this_thread::sleep_until (chrono::system_clock::time_point)

this_thread::sleep_for(chrono::system_clock::seconds(xxx))
(或其他时间单位)
可以控制具体的睡眠时间

2.thread::swap(thread &Other)
和另一个线程交换上下文
等价于
swap(thread &Left,thread &Right);
3.move(thread &t)
构造函数
参数被move之后就不再是线程了。相当于把参数中的线程上下文“抢”了过来
4.get_id()
如果线程是joinable的,则会返回一个id(其实就是个无符号32位?)
当已经执行过了,或者被move走了等,即joinable==false时,返回的是0
在这里插入图片描述

class ThreadOtherTest {
public:
	thread h;
	thread w;
	void hello() {
		cout << "Hello";
	}
	void World() {
		cout << " World" << endl;
	}
	void test() {
		thread hellothread(&ThreadOtherTest::hello, this);
		hellothread.swap(h);
		h.join();

		thread worldthread(&ThreadOtherTest::World, this);
		swap(w, worldthread);
		w.join();

		thread m([] {
			auto tp = chrono::system_clock::now();
			tp += chrono::seconds(4);
			this_thread::sleep_until(tp);
			this_thread::sleep_for(chrono::seconds(1));
			cout << "test" << endl;
			int t = 0;
			while (t++ < 10) {
				cout << "Sleeping" << endl;
				Sleep(1000);
			}
			});
		cout << "m id:" << m.get_id() << endl;
		thread m2(move(m));
		cout << "after m2 move(m)" << m.get_id() << endl;
		cout << "mainid:" << this_thread::get_id() << endl;
		cout << "m2id:" << m2.get_id() << endl;
		m2.join();
		cout << "after m2 join" << m2.get_id() << endl;
	}
};

在这里插入图片描述

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值