第五章 Unique Lock and Lazy Initialization
来源:互联网 发布:淘宝销售数据 编辑:程序博客网 时间:2024/06/05 00:09
本章学习重点:
Unique Lock
线程环境中处理初始化问题
前面介绍过两点"加锁"的方式:一个是使用mutex,另一个是lock_guard<std::mutex>,还有另外一种方式是使用unique_lock.
lock_guard 最大的缺点也是简单,没有给程序员提供足够的灵活度,因此,C++11 标准中定义了另外一个与 Mutex RAII 相关类 unique_lock,该类与 lock_guard 类相似,也很方便线程对互斥量上锁,但它提供了更好的上锁和解锁控制。
From <http://www.cnblogs.com/haippy/p/3346477.html>
黄棒清使用的一词——"弹性",来表示unique_lock的优点。比如在案例中cout后面执行其他代码,但是该代码不需要mutex被锁住,可是使用unlocker解锁。
std::unique_lock<std::mutex> locker(m_mutex);
//std::lock_guard<mutex> locker(m_mutex);
std::cout<< "from " << id << value << endl;
locker.unlock();
//......
而unique_lock还有一个参数defer_lock,可以将该锁打开,在使用之前,直接lock一下就可以。
std::unique_lock<std::mutex> locker(m_mutex, defer_lock);
//.....
//std::lock_guard<mutex> locker(m_mutex);
locker.lock();//locker这把锁锁上下面的cout,但上面//......中的其他代码并没有上锁
std::cout<< "from " << id << value << endl;
locker.unlock();
//......
测试结果:
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.
From <http://www.cplusplus.com/reference/mutex/unique_lock/>
std::unique_lock移动(move assign)赋值操作
std::unique_lock支持移动赋值(move assignment),但是普通的赋值被禁用了,
move (1)
unique_lock& operator= (unique_lock&& x) noexcept;
copy [deleted] (2)
unique_lock& operator= (const unique_lock&) = delete;
移动赋值(move assignment)之后,由 x所管理的 Mutex 对象及其状态将会被新的 std::unique_lock对象取代。
From <http://www.cnblogs.com/haippy/p/3346477.html>
Member types
member type
definition
description
mutex_type
The template parameter (Mutex)
The managed mutex object type
Member functions
(constructor)
Construct unique_lock (public member function )
(destructor)
Destroy unique_lock (public member function )
Locking/unlocking
lock
Lock mutex (public member function )
try_lock
Lock mutex if not locked (public member function )
try_lock_for
Try to lock mutex during time span (public member function )
try_lock_until
Try to lock mutex until time point (public member function )
unlock
Unlock mutex (public member function )
Modifiers
operator=
Move-assign unique_lock (public member function )
swap
Swap unique locks (public member function )
release
Release mutex (public member function )
Observers
owns_lock
Owns lock (public member function )
operator bool
Return whether it owns a lock (public member function )
mutex
Get mutex (public member function )
From <http://www.cplusplus.com/reference/mutex/unique_lock/>
#include <iostream> // std::cout
#include <thread> // std::thread
#include <mutex> // std::mutex, std::unique_lock
std::mutex mtx; // mutex for critical section
void print_block(int n, char c) {
// critical section (exclusive access to std::cout signaled by lifetime of lck):
std::unique_lock<std::mutex> lck(mtx);
for (int i = 0; i<n; ++i) { std::cout << c; }
std::cout << '\n';
}
int main()
{
std::thread th1(print_block, 5000, '*');
std::thread th2(print_block, 500, '$');
th1.join();
th2.join();
return 0;
}
图一:使用defer_lock,但没有lock时的结果
图二:使用cout之前locker这把锁锁上了cout的结果
Lazy Initialization
在上面的上面的例子中,f.open()在构造时就会被打开一次,而对于不需要的情况下再次的打开显然是浪费资源,因此,移动到下面的成员函数中:
void share_Print(std::string id, int value)
{
If(!f.is_open())
{
f.open("log.txt");
}
std::unique_lock<std::mutex> locker(m_mutex);
//std::lock_guard<mutex> locker(m_mutex);
std::cout<< "from " << id << value << endl;
}
但是,同cout一样,open也需要使用锁来保证线程的安全,
//…….
Mutex m_mutex_open;
void share_Print(std::string id, int value)
{
If(!f.is_open())
{
std::unique_lock<std::mutex> locker(m_mutex_open);
f.open("log.txt");
}
std::unique_lock<std::mutex> locker(m_mutex,std::defer_lock);
//std::lock_guard<mutex> locker(m_mutex);
std::cout<< "from " << id << value << endl;
}
这种情况也同样不能保证线程的安全,这是由于is_open()函数没有使用锁来保护该资源,导致多个线程同时因为抢占is_open函数时而导致死锁的发生。进一步修改上述代码
#include<iostream>
#include<string>
#include<thread>
#include<mutex>
#include<fstream>
using namespace std;
std::mutex mu;
class lofFile
{
public:
lofFile()
{
//f.open("log.txt");//构造函数中打开log.txt文件
}
void share_Print(std::string id, int value)
{
{
std::unique_lock<std::mutex> locker(m_mutex1);
if (!f.is_open())
{
f.open("log.txt");
}
}
std::unique_lock<std::mutex> locker(m_mutex);
//std::lock_guard<mutex> locker(m_mutex);
std::cout<< "from " << id << value << endl;
}
protected:
private:
mutex m_mutex;
mutex m_mutex1;
ofstream f; //被m_mutex保护的对象
};
void function_1(lofFile& l)
{
for (int i = 0; i > -100; i--)
{
//std::cout << "From t1:" << i << std::endl;
//using shared_Print function instead of function_1
l.share_Print("From t1", i);
}
}
int main()
{
lofFile l;
thread t1(function_1, std::ref(l));
for (int i = 0; i < 100; i++)
{
//cout << "From main:" << i << endl;
l.share_Print("From Main()", i);
}
t1.join();
}
为了简洁起见,C++11委员会人员提供一种解决方案。使用lazy initialization
将上面的
mutex m_mutex1;
修改为std::once_flag m_flag;将锁和文件使用lambda来代替(能够保证一个线程只能被调用一次):
std::call_once(m_flag, [&]() {f.open("log.txt"); });
清单:使用lazy initializatin
#include<iostream>
#include<string>
#include<thread>
#include<mutex>
#include<fstream>
using namespace std;
std::mutex mu;
class lofFile
{
public:
lofFile()
{
//f.open("log.txt");
}
void share_Print(std::string id, int value)
{
//{
//std::unique_lock<std::mutex> locker(m_mutex1, defer_lock);
//if (!f.is_open())
//{
//f.open("log.txt");
//}
//}
//直接使用m_flag
std::call_once(m_flag, [&]() {f.open("log.txt"); });
std::unique_lock<std::mutex> locker(m_mutex, defer_lock);
//.....
//std::lock_guard<mutex> locker(m_mutex);
locker.lock();//locker这把锁锁上下面的cout,但上面//......中的其他代码并没有上锁
std::cout<< "from " << id << value << endl;
locker.unlock();
//......
}
protected:
private:
mutex m_mutex;
mutex m_mutex1;
std::once_flag m_flag;
ofstream f; //被m_mutex保护的对象
};
void function_1(lofFile& l)
{
for (int i = 0; i > -100; i--)
{
//std::cout << "From t1:" << i << std::endl;
//using shared_Print function instead of function_1
l.share_Print("From t1", i);
}
}
int main()
{
lofFile l;
thread t1(function_1, std::ref(l));
for (int i = 0; i < 100; i++)
{
//cout << "From main:" << i << endl;
l.share_Print("From Main()", i);
}
t1.join();
}
测试结果:
- 第五章 Unique Lock and Lazy Initialization
- Lazy initialization
- Lazy Initialization
- Lazy Initialization and the DAO pattern with Hibernate and Spring
- Lazy Initialization and the DAO pattern with Hibernate and Spring(1)
- Lazy Initialization and the DAO pattern with Hibernate and Spring (2)
- Lazy Initialization and the DAO pattern with Hibernate and Spring (3)
- Lazy initialization holder class模式
- Lazy initialization的一个问题
- Lazy initialization holder class模式
- 惰性初始模式 Lazy Initialization
- thread safe lazy initialization singleton
- Lazy initialization holder class模式
- Lazy Initialization and the DAO pattern with Hibernate and Spring(Spring 与Hibernate的延迟加载和Dao模式)
- 第十章 Project Setup and Window Initialization
- Hibernate种Lazy Initialization的问题
- Hibernate入门24 - 延迟初始 Lazy Initialization
- Use lazy initialization judiciously(明智地使用)
- AndroidStudio插件推荐
- JUC原子类 Atomic***** 基本类型
- java中的类,属性,方法修饰符及其作用
- 【Android】长按连续触发事件的实现方法
- java知识点5
- 第五章 Unique Lock and Lazy Initialization
- Java中Collections.sort()排序详解
- 二十岁出头,你一无所有,但你却拥有一切(转载)
- 浅谈Java中的equals和==
- 欧几里得算法(+扩展)
- 10个免费的javascript富文本编辑器(jQuery and non-jQuery)
- 有两个磁盘文件“A"和”B",各存放一行字母,先要求把这两个文件中的信息合并(按字母顺序排列),输出到一个新文件“C"中去。
- 我的IT相关网址收藏
- Java知识点6