码迷,mamicode.com
首页 > 编程语言 > 详细

[C++11 并发编程] 05 Mutex 基本操作

时间:2015-08-09 20:42:19      阅读:218      评论:0      收藏:0      [点我收藏+]

标签:c++11   并发   mutex   lock_guard   

Mutex是C++中最常见的数据保护机制之一,在访问一块共享数据前,lock mutex,在完成对数据的访问后,unlock mutex。线程库当一个特定mutex被某个线程lock后,其它尝试lock同一个mutex的线程都会被挂起指导这个mutex被unlock。这就保证了所有线程看到的数据都是完整的,不会被修改了一部分的数据。


在C++中,通常我们通过创建std::mutex的实例来获得一个mutex,调用它的成员函数lock()来锁住它,调用unlock来解锁,但实际实现时,并不推荐这么写,因为这需要我们记住所有需要调用unlock()的代码分支,包括异常分支。 C++标准库提供了std::lock_guard模版类,它在构造函数做锁住mutex,在析构函数中解锁,下面是一个使用std::lock_guard来保护被多个线程访问的链表的实例。


#include "stdafx.h"

#include <list>
#include <mutex>
#include <algorithm>

// 全局变量链表
std::list<int> some_list;
// 全局变量mutex
std::mutex some_mutex;

void add_to_list(int new_value)
{
	// 使用lock_guard来保护链表
	std::lock_guard<std::mutex> guard(some_mutex);
	some_list.push_back(new_value);
}
bool list_contains(int value_to_find)
{
	// 使用lock_guard来保护链表
	std::lock_guard<std::mutex> guard(some_mutex);
	return std::find(some_list.begin(), some_list.end(), value_to_find)
		!= some_list.end();
}

#include <iostream>

int main()
{
	add_to_list(42);
	std::cout << "contains(1)=" << list_contains(1) << ", contains(42)=" << list_contains(42) << std::endl;
}

通常,将mutex, add_to_list和list_contains作为某个类的成员变量和成员函数比把它们作为全局变量更好,因为这样,mutex和它要保护的数据的相关性更加明确。添加其它要访问共享数据的成员函数时,也需要在这些新加的函数中创建lock_guard实例。但是,有一点还是需要注意,如果某个成员函数返回一个共享数据的指针或引用,就会导致被保护的数据可能被意外的访问或修改,在设计接口时,应该尽量避免这种情况。


下面一个例子是一个将受保护数据交给用户自定义函数而导致风险的例子:

#include <mutex>

class some_data
{
	int a;
	std::string b;
public:
	void do_something()
	{}
};

class data_wrapper
{
private:
	some_data data;
	std::mutex m;
public:
	template<typename Function>
	void process_data(Function func)
	{
		std::lock_guard<std::mutex> l(m);
		func(data);
	}
};

some_data* unprotected;

void malicious_function(some_data& protected_data)
{
	unprotected = &protected_data;
}

data_wrapper x;

void foo()
{
	x.process_data(malicious_function);
	unprotected->do_something();
}

int main()
{
	foo();
}
在这个例子中,process_data kan看起没啥问题,它使用std::lock_gurad来保护数据,但是调用用户定义的函数func意味着foo可以传入malicious_function来绕过保护,而调用do_something()为不对数据进行lock操作。不仅仅如此,这段代码还有其它问题,比如foo() 中调用unprotected->do_something()也需要对数据进行加锁。对正确的mutex执行加锁操作是所有程序员需要做到的,其基本准则是:

不要将指向受保护数据的指针或引用传递到lock控制范围的外部,比如,通过函数返回值,使用另外的指针或引用来存储受保护数据或将它们作为参数传给其它的函数。



版权声明:本文为博主原创文章,未经博主允许不得转载。

[C++11 并发编程] 05 Mutex 基本操作

标签:c++11   并发   mutex   lock_guard   

原文地址:http://blog.csdn.net/yamingwu/article/details/47379111

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!