C++11 介绍 mutex(互斥)

2014-01-19

首先看mutex头文件里面有的内容,如下表:

Classes  
Mutexes  
mutex Mutex class (class )  
recursive_mutex Recursive mutex class (class )
timed_mutex Timed mutex class (class )
recursive_timed_mutex Recursive timed mutex (class )
   
Locks  
lock_guard Lock guard (class template )
unique_lock Unique lock (class template )
   
Other types  
once_flag Flag argument type for call_once (class )
adopt_lock_t Type of adopt_lock (class )
defer_lock_t Type of defer_lock (class )
try_to_lock_t Type of try_to_lock (class )
   
Functions  
try_lock Try to lock multiple mutexes (function template )
lock Lock multiple mutexes (function template )
call_once Call function once (public member function )

 

---------------------------------------------------------------------------

mutex类


Mutex class
A mutex is a lockable object that is designed to signal when critical sections of code need exclusive access, preventing other threads with the same protection from executing concurrently and access the same memory locations.

mutex objects provide exclusive ownership and do not support recursivity (i.e., a thread shall not lock a mutex it already owns) -- see recursive_mutex for an alternative class that does.

It is guaranteed to be a standard-layout class.

(constructor) Construct mutex (public member function )
lock Lock mutex (public member function )
try_lock Lock mutex if not locked (public member function )
unlock Unlock mutex (public member function )
native_handle Get native handle (public member function )

从Menber functions说起:

(constructor)               构造函数  负责线程对象的初始化构造。

lock                                锁互斥变量。

try_lock                          尝试锁互斥变量。

unlock                            解锁互斥变量。

native_handle                  返回当前句柄,句柄指的是一个核心对象在某一个进程中的唯一索引。

#include <iostream>
#include <thread>        
#include <mutex>
#include <windows.h>
using namespace std;
mutex mtx;   // 定义了一个互斥量  mtx


// -------------lock()-----------------------
void print_block(int n, char c) {       
	// 定义了一个临界区,意味着mtx上了锁,独占访问(单独占有这个区域,并且只有此区域可以访问区域内的数据)
	mtx.lock();
	for (int i = 0; i<n; ++i) { std::cout << c; }
	cout << '\n';
	mtx.unlock();
}
void main_print_block()
{
	std::thread th1(print_block, 50, '*');
	std::thread th2(print_block, 50, '$');
	th1.join();
	th2.join();
}

volatile int sum(0);
void attempt_20k_increases()
{
	for (int i = 0; i<20000; ++i)
	{
		if (1)
		{   // 上锁操作
			mtx.lock();
			++sum;
			mtx.unlock();
		}
	}
}
void main_attempt_lock()
{
	thread threads[10];
	// 产生10个线程
	for (int i = 0; i<10; ++i)
		threads[i] = thread(attempt_20k_increases);
	for (auto& th : threads)
		th.join();
	cout << sum << " successful increases of the counter.\n";
}


// -------------try_lock()-----------------------
// ----如果能上锁,就执行区域内代码,否则pass--
void print_thread_id(int id) {
     sleep(50) if (mtx.try_lock()){ cout << "thread " << id << '\n'; mtx.unlock(); }
     else
       cout << "not running thread " << id << endl;
} void main_lock() { thread threads[10]; for (int i = 0; i<10; ++i) threads[i] = thread(print_thread_id, i + 1); for (auto& th : threads) th.join(); } volatile int counter(0); void attempt_10k_increases() { for (int i = 0; i<10000; ++i) { if (mtx.try_lock()) { ++counter; mtx.unlock(); } } } void main_attempt() { thread threads[10]; for (int i = 0; i<10; ++i) threads[i] = thread(attempt_10k_increases); for (auto& th : threads) th.join(); cout << counter << " successful increases of the counter.\n"; } void main() { cout << "演示 lock()" << endl; main_print_block(); cout << endl; cout << "演示 lock()" << endl; main_attempt_lock(); cout << endl; cout << "演示 try_lock()" << endl; main_lock(); cout << endl; cout << "演示 try_lock()" << endl; main_attempt(); cout << endl; }

这个例子中显示,列出了2个关于lock(),2个关于unlock()的例子。

lock()的意思是,锁上mtx,才可以执行区域内代码。(unclear)

try_lock()的意思是,如果mtx是上锁的状态,就执行区域内代码,否则跳过此区域,执行下面顺序的代码。


代码执行结果:

演示 lock()
**************************************************
$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$

演示 lock()
200000 successful increases of the counter.

演示 try_lock()
not running thread 4
not running thread 5
not running thread 8
not running thread 9
not running thread 2
not running thread 10
not running thread 7
thread 6
not running thread 1
not running thread 3

演示 try_lock()
18702 successful increases of the counter.

请按任意键继续. . .

 

 

 

 

---------------------------------------------------------------------------

recursive_mutex类

 

Recursive mutex class
A recursive mutex is a lockable object, just like mutex, but allows the same thread to acquire multiple levels of ownership over the mutex object.

This allows to lock (or try-lock) the mutex object from a thread that is already locking it, acquiring a new level of ownership over the mutex object: the thread will remain locked until member unlock is called as many times as this level of ownership.

It is guaranteed to be a standard-layout class.

 

recursive_mutex 意思是递归锁类,recursive_mutex 类的对象例如 mtx ,可以上锁多次,但是解锁必须匹配上锁的次数,才能保证不死锁。

普通的mutex类的对象 mtx,不可能多次上锁。recursive_mutex 的函数功能与 mutex 基本一样。

(constructor) Construct recursive mutex (public member function )
lock Lock recursive mutex (public member function )
try_lock Lock recursive mutex if not locked (public member function )
unlock Unlock recursive mutex (public member function )
native_handle Get native handle (public member function )

从Menber functions说起:

(constructor)               构造函数  负责线程对象的初始化构造。

lock                                锁互斥变量。

try_lock                          尝试锁互斥变量。

unlock                            解锁互斥变量。

native_handle                  返回当前句柄,句柄指的是一个核心对象在某一个进程中的唯一索引。

下面这两个函数显示了recursive_mutex 类的含义。

#include <iostream>       
#include <thread>         
#include <mutex>        
#include <windows.h>
using namespace std;
volatile int counter(0);

recursive_mutex mtx;           
mutex mtx_1;
void attempt_10k_increases()
{
	for (int i = 0; i<1; ++i) 
	{
		if (1)
		{
			mtx.lock();
			cout << "lock 1 time" << endl;
			mtx.lock();
			cout << "lock 2 times" << endl;
			++counter;
			cout << counter << endl;
			mtx.unlock();
			cout << "unlock 1 time" << endl;
			mtx.unlock();
			cout << "unlock 2 times" << endl;
			cout << "------------------------" << endl;
			Sleep(50);
		}
	}
}

void main_attempt_10k()
{
	thread threads[3];
	for (int i = 0; i<3; ++i)
		threads[i] = thread(attempt_10k_increases);
	for (auto& th : threads) 
		th.join();
	cout << counter << " successful increases of the counter.\n";
}


void attempt_10k_increases_try_lock()
{
	for (int i = 0; i<10000; ++i)
	{
		if (mtx.try_lock())
		{
			if (mtx.try_lock())
			{
				++counter;
				mtx.unlock();
				mtx.unlock();
			}
		}
	}
}

void main_attempt_10k_try_lock()
{
	thread threads[10];
	for (int i = 0; i<10; ++i)
		threads[i] = thread(attempt_10k_increases_try_lock);
	for (auto& th : threads)
		th.join();
	cout << counter << " successful increases of the counter.\n";
}



void main()
{
	main_attempt_10k();
	cout << "\n\n" << endl;
	main_attempt_10k_try_lock();
}

代码结果:

lock 1 time
lock 2 times
1
unlock 1 time
unlock 2 times
lock 1 time
------------------------
lock 2 times
2
unlock 1 time
unlock 2 times
------------------------
lock 1 time
lock 2 times
3
unlock 1 time
unlock 2 times
------------------------
3 successful increases of the counter.

 

13663 successful increases of the counter.

 

 

---------------------------------------------------------------------------

timed_mutex类

 

Timed mutex class
A timed mutex is a time lockable object that is designed to signal when critical sections of code need exclusive access, just like a regular mutex, but additionally supporting timed try-lock requests.

As such, a timed_mutex has two additional members: try_lock_for and try_lock_until.

It is guaranteed to be a standard-layout class.

 

(constructor) Construct  timed mutex (public member function )
lock Lock  timed mutex (public member function )
try_lock Lock  timed mutex if not locked (public member function )
unlock Unlock  timed mutex (public member function )
native_handle Get native handle (public member function )
try_lock_for Try to lock for time span (public member function )
try_lock_until Try to lock until time point (public member function )

从Menber functions说起:

(constructor)               构造函数  负责线程对象的初始化构造。

lock                                锁互斥变量。

try_lock                          尝试锁互斥变量。

try_lock_for                    尝试在给定时间内lock 这个 mtx 一次

try_lock_until       尝试在给定时间点内锁这个mtx,如果锁成,就返回 true,否则 fasle

unlock                            解锁互斥变量。

native_handle                  返回当前句柄,句柄指的是一个核心对象在某一个进程中的唯一索引。

 执行代码:

#include <iostream>       
#include <thread>   
#include <chrono> 
#include <mutex>     
#include <ctime> 
#include <windows.h>
using namespace std;
#pragma warning( disable : 4996 )

int counter = 0;
mutex mmtx;
timed_mutex mtx;
void fireworks() {
	while (!mtx.try_lock_for(chrono::milliseconds(498))) 
	//尝试在0.49s内lock 这个 mtx 一次,如果没锁成,就打印一个“-”
	//如果锁成,就跳出while,按顺序执行下面语句。
	//和try_lock()的区别,try_lock_for()是在给定的时间内,执行一次锁动作
	//try_lock()是 只要时间片转到这个线程上,就执行,可以说成无限尝试 try_lock()动作
	{    
	//while (!mmtx.try_lock()) {
		cout <<"-";
		counter++;
	}
	auto first_counter = counter;
	cout << endl;
	// got a lock! - wait for 1s, then this thread prints "*"
	this_thread::sleep_for(chrono::milliseconds(1000));
	cout <<counter - first_counter<< "*\n";
	mtx.unlock();
}

void main_fireworks()
{
	thread threads[10];
	for (int i = 0; i<10; ++i)
		threads[i] = thread(fireworks);
	for (auto& th : threads) 
		th.join();
}



timed_mutex cinderella;
// gets time_point for next midnight:
chrono::time_point<std::chrono::system_clock> midnight() 
{
	using chrono::system_clock;
	time_t tt = system_clock::to_time_t(system_clock::now());
	struct tm *ptm = localtime(&tt);
	++ptm->tm_mday; 
	ptm->tm_hour = 0; 
	ptm->tm_min = 0; 
	ptm->tm_sec = 0;
	return system_clock::from_time_t(mktime(ptm));
}
void carriage() {
	if (cinderella.try_lock_until(midnight())) {
		cout << "ride back home on carriage\n";
		cinderella.unlock();
	}
	else
		cout << "carriage reverts to pumpkin\n";
}
void ball() {
	cinderella.lock();
	cout << "at the ball...\n";
	cinderella.unlock();
}
void main_try_lock_until()
{
	thread th1(ball);
	thread th2(carriage);

	th1.join();
	th2.join();
}


void main()
{
	main_fireworks();
	cout << endl;
	main_try_lock_until();
}

执行结果:


------------------18*

----------------16*

--------------14*

------------12*

----------10*

--------8*

------6*

----4*

--2*

0*

at the ball...
ride back home on carriage
请按任意键继续. . .

这两端代码说明了,try_lock_for()在给定时间内只尝试执行1次的特性,和try_lock_until()在给定时间点内,执行起来和try_lock()一样。

 

---------------------------------------------------------------------------

recursive_timed_mutex类

 

Recursive timed mutex
A recursive timed mutex combines both the features of recursive_mutex and the features of timed_mutex into a single class: it supports both acquiring multiple lock levels by a single thread and also timed try-lock requests.

It is guaranteed to be a standard-layout class.

综合recursive_mutex 和 timed_mutex 和 mutex 的特性,可以在给定时间范围内上递归锁,可以在给定时间点内上递归锁。

 

 

---------------------------------------------------------------------------

lock_guard类

 

Lock guard
A lock guard is an object that manages a mutex object by keeping it always locked.

On construction, the mutex object is locked by the calling thread, and on destruction, the mutex is unlocked. It is the simplest lock, and is specially useful as an object with automatic duration that lasts until the end of its context. In this way, it guarantees the mutex object is properly unlocked in case an exception is thrown.

Note though that the lock_guard object does not manage the lifetime of the mutex object in any way: the duration of the mutex object shall extend at least until the destruction of the lock_guard that locks it.

lock_guard 比喻成一个 lock 的守卫,负责自动给语句区域内的 mtx 对象上锁解锁。

下面代码说明了调用 lock_guard<mutex> lck(mtx) 后,守卫会自动上锁,解锁。

代码如下:

mutex mtx;
void print_even(int x) 
{
	if (x % 2 == 0) 
		cout << x << " is even\n";
	else 
		throw (logic_error("not even"));
}
void print_thread_id(int id) 
{
	try {
		lock_guard<mutex> lck(mtx);
		print_even(id);
	}
	catch (logic_error&) {
		cout << "[exception caught]\n";
	}
}
void main()
{
	thread threads[10];
	for (int i = 0; i<10; ++i)
		threads[i] = thread(print_thread_id, i + 1);
	for (auto& th : threads) 
		th.join();
}

结果如下:

[exception caught]
2 is even
[exception caught]
4 is even
[exception caught]
6 is even
[exception caught]
8 is even
[exception caught]
10 is even
请按任意键继续. . .

 

 

---------------------------------------------------------------------------

unique_lock类

 

Unique lock
A unique lock is an object that manages a mutex object with unique ownership in both states: locked and unlocked.

On construction (or by move-assigning to it), the object acquires a mutex object, for whose locking and unlocking operations becomes responsible.

The object supports both states: locked and unlocked.

This class guarantees an unlocked status on destruction (even if not called explicitly). Therefore it is especially useful as an object with automatic duration, as it guarantees the mutex object is properly unlocked in case an exception is thrown.

Note though, that the unique_lock object does not manage the lifetime of the mutex object in any way: the duration of the mutex object shall extend at least until the destruction of the unique_lock that manages it.

 

unique_lock 有和 lock_guard 一样的功能外,(lock_guard在离开作用域时unlock它guard的mutex)。unique还提供unlock函数,使用者可以手动执行unlock。此外,unique_lock还可以设置超时。

---------------------------------------------------------------------------

Functions

lock                                锁互斥变量。

try_lock                          尝试锁互斥变量。

call_once                         用于保证某个函数不被多个线程同时执行。

用于保证某个函数不被多个线程同时执行,传入的  call_once(winner_flag, set_winner, id);  三个参数为  标志,导入函数,导入函数的参数

int winner;
void set_winner(int x) { winner = x; }
once_flag winner_flag;

void wait_1000ms(int id) {
	// count to 1000, waiting 1ms between increments:
	for (int i = 0; i<1000; ++i)
		this_thread::sleep_for(chrono::milliseconds(1));
	// claim to be the winner (only the first such call is executed):
	call_once(winner_flag, set_winner, id);
}

int main()
{
	thread threads[10];
	// spawn 10 threads:
	for (int i = 0; i<10; ++i)
		threads[i] = thread(wait_1000ms, i + 1);

	cout << "waiting for the first among 10 threads to count 1000 ms...\n";

	for (auto& th : threads) th.join();
		cout << "winner thread: " << winner << '\n';
	return 0;
}

代码结果:

waiting for the first among 10 threads to count 1000 ms...
winner thread: 3
请按任意键继续. . .

 

 

 

posted on 2014-01-19 22:07  WK23  阅读(1779)  评论(0)    收藏  举报

导航