栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > C/C++/C#

C++多线程与mutex

C/C++/C# 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

C++多线程与mutex

目录

线程的创建

1.对函数创建线程

​2.对类里面创建线程

3.对成员函数创建变量

4.多线程的创立

Mutex

1.一般互斥锁

2.lock_guard

3.unique_lock 

条件变量


线程的创建

线程的创建需要#include ,格式为thread mythread(....)

1.对函数创建线程

格式为thread mythread(function,variable1,variable2,...)

#include 
#include 
using namespace std;
void fuction(int a, int b) {
	cout << "enter the subthread:";
	cout << a << b << endl;
}
int main(void) {
	cout << "in main thread" << endl;
	thread mythread(fuction, 2, 9);
	mythread.join();
	cout << "in main thread" << endl;
}

2.对类里面创建线程

格式为thread mythread(classvariable,variables);这里似乎一定要重载括号。

#include 
#include 
#include 
using namespace std;
class X
{
public:
	X() { cout << "constructor!" << endl; }
	X(const X& m) { cout << "copy constructor called !" << endl; }
	void operator()(int a)   // 重载括号运算符。如果无参则为void operator()(){...}
	{
		cout << "start!" << a << endl;
	}
};

int main()
{
	X a;
	thread p(a, 4);  //以对象a创建线程,并传递参数4,无参的话直接省略第二个参数,更多的参数直接加在后面
	p.join();
	return 0;
}

3.对成员函数创建变量

格式为thread mythread(&class::function,&classvariable,variables_of_function)

#include 
#include 
#include 
using namespace std;
class X
{
public:
	X() { cout << "constructor!" << endl; }
	X(const X& m) { cout << "copy constructor called !" << endl; }
	void coutdata(int a, int d) {
		cout << a << '&' << d << endl;
	}
};

int main()
{
	X a;
	thread p(&X::coutdata,&a,3,4);  //以对象coutdata创建线程,并传递参数3、4,
									//无参的话直接省略第二个参数,更多的参数直接加在后面
	p.join();
	return 0;
}

 

4.多线程的创立

只要同时使用多个thread创建,再逐一join便可。mythread.join();表示阻塞主线程,等子线程运行完再运行主线程,可join多个子线程。这时便进行了多线程运行,如果两个线程同时对一个变量进行操作则需要下面的mutex。C++ 多线程join()和detach()的理解_皮皮#2500-CSDN博客_c++线程detach

Mutex

锁是把在lock和unlock之间的代码锁起来,如果涉及到几个线程共同涉及到一个变量,锁便起了大作用。需要#include 。没有加锁:

#include 
#include 
#include 
#include 
#include 
using namespace std;
class List {
private:
	list mylist;
	mutex mlock;
	int i = 0;
public:
	void WriteList()
	{
		while (i < 1000)
		{
			mylist.push_back(i++);
		}
		return;
	}
	void showList()
	{
		for (auto p = mylist.begin(); p != mylist.end(); p++)
		{
			cout << (*p) << " ";
		}
		cout << endl;
		cout << "size of list : " << mylist.size() << endl;
		return;
	}
};
int main()
{
	List mlist;
	thread pwrite0(&List::WriteList, &mlist);
	thread pwrite1(&List::WriteList, &mlist);

	pwrite0.join();
	pwrite1.join();
	cout << "threads end!" << endl;

	mlist.showList();  //子线程结束后主线程打印list
	return 0;
}

改自:

1.一般互斥锁

1. 原子性:把一个互斥量锁定为一个原子操作,这意味着如果一个线程锁定了一个互斥量,没有其他线程在同一时间可以成功锁定这个互斥量;

2. 唯一性:如果一个线程锁定了一个互斥量,在它解除锁定之前,没有其他线程可以锁定这个互斥量;

3. 非繁忙等待:如果一个线程已经锁定了一个互斥量,第二个线程又试图去锁定这个互斥量,则第二个线程将被挂起(不占用任何cpu资源),直到第一个线程解除对这个互斥量的锁定为止,第二个线程则被唤醒并继续执行,同时锁定这个互斥量。

 互斥锁将mlock.lock()和mlock.unlock()之间锁住;

#include 
#include 
#include 
#include 
#include 
using namespace std;
class List {
private:
	list mylist;
	mutex mlock;
	int i = 0;
public:
	void WriteList()
	{
		while (i < 1000)
		{
			mlock.lock();
			if (i >= 10000)
			{
				mlock.unlock();   //退出之前必须先解锁
				break;
			}
			mylist.push_back(i++);
			mlock.unlock();
		}
		return;
	}
	void showList()
	{
		for (auto p = mylist.begin(); p != mylist.end(); p++)
		{
			cout << (*p) << " ";
		}
		cout << endl;
		cout << "size of list : " << mylist.size() << endl;
		return;
	}
};
int main()
{
	List mlist;
	thread pwrite0(&List::WriteList, &mlist);
	thread pwrite1(&List::WriteList, &mlist);

	pwrite0.join();
	pwrite1.join();
	cout << "threads end!" << endl;

	mlist.showList();  //子线程结束后主线程打印list
	return 0;
}

2.lock_guard

lock_guard就是一个类,它会在lock_guard的构造函数中加锁,而在析构函数中解锁,也就是说,只要创建一个lock_guard的对象,就相当于lock()了,而该对象析构时,就自动调用unlock()了。

void WriteList()
	{
		while(i<10000)
		{
                        lock_guard guard(mlock);  //创建lock_guard的类对象guard,用互斥量m来构造
			//mlock.lock();   
			if (i >= 10000)
			{
				//mlock.unlock();   //由于有了guard,这里就无需unlock()了
				break;
			}
			mylist.push_back(i++);
			//mlock.unlock();
		}
		return;
	}

3.unique_lock 

unique_lock和上面的规则差不多,不过他生命期内允许手动加锁和释放锁。图来自:

这里说明一下unique_lock是给原先有的一个mutex类型(比如叫mlock)再套上一层,

unique locker(mlock)。使mlock变为名字为locker的特殊锁,对其解锁时用的是:

locker.unlock();而非mlock.unlock(); 

条件变量

copy_from

条件变量使用“通知—唤醒”模型,生产者生产出一个数据后通知消费者使用,消费者在未接到通知前处于休眠状态节约CPU资源;当消费者收到通知后,赶紧从休眠状态被唤醒来处理数据,使用了事件驱动模型,在保证不误事儿的情况下尽可能减少无用功降低对资源的消耗。

  • 那个通知“条件已满足”的线程(或多个线程之一)必须调用notify_one()或notify_all(),以便条件满足时唤醒处于等待中的一个条件变量;
  • 那个等待"条件被满足"的线程必须调用wait(),可以让线程在条件未被满足时陷入休眠状态,当接收到通知时被唤醒去处理相应的任务
#include 
#include 	//双端队列
#include 
#include 

using namespace std;
deque q;
mutex mu;
condition_variable cond;

void productor() {
	int count = 10;
	while (count > 0) {
		unique_lock locker(mu);
		q.push_front(count);
		locker.unlock();
		cond.notify_one();
		this_thread::sleep_for(chrono::seconds(1));
		count--;
	}
}

void consumer() {
	int data = 0;
	while (data != 1) {
		unique_lock locker(mu);
		while (q.empty()) {
			cond.wait(locker);
		}
		data = q.back();
		q.pop_back();
		locker.unlock();
		std::cout << "t2 got a value from t1: " << data << std::endl;
	}
}
int main(void) {
	thread t1(productor);
	thread t2(consumer);
	t1.join();
	t2.join();
	
	return 0;
}

 

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/396309.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号