共享平台的竞争分析,数据共享技术
共享数据竞赛布局:posttitle:多线程共享数据竞赛3354初始化和读写锁类别:CPP _ Concurrency描述:C并发编程简介关键词:C并发编程std:once_flag、std:once_call
共享数据竞争关键词:c、并发编程、std:once_flag、std:once_call初始化竞争std:once_flag和std:call_once静态初始化竞争读写锁。如果某个数据需要在多线程共享之前进行初始化,或者某个资源大部分时间是只读的,那么这个时候使用互斥体会造成很大的性能浪费。在传统的系统编程中,可以使用读写锁,但是C 11标准并没有在标准库中包含读写锁。虽然没有提供读写锁,但是我们可以很容易地实现自己的读写锁。同时,C 11标准库还提供了数据初始化操作3354STD: once _ flag和STD: std:once_call——,保证相关操作只在一个线程上完成。
std:once_flag和std:call_once的标准库提供了std:once_flag和STD: call _ once,一般用于条件初始化。相比锁互斥和显式检查指针,每个线程只需要使用std:call_once。在std:call_once的结尾,保证相关资源已经安全初始化。使用std:call_once比显式使用互斥锁消耗更少的资源,尤其是在初始化之后。
为什么调用call_once后资源在线程安全中初始化?实际上,cpp保证std:call_once的调用和执行是线程安全的。至于你想在这个功能里做什么,那是你自己的事。如果你没有初始化其中的相关资源,那么程序就无法按照你的预期执行。
STD:shared _ ptr some _ resource resource _ ptr;
std:once_flag资源_标志;//1
void初始化资源()
{
resource _ ptr . reset(new some _ resource);
}
void foo()
{
std:call_once(资源_标志,初始化_资源);//可以执行一次完整的初始化。
resource _ ptr-do _ something();
}清单3.12延迟初始化使用std:call_once作为类成员(线程安全)。其实实现我们自己的call_once也很简单。我们只需要提供一个原子变量std:atomit bool作为标志来判断是否初始化。不过既然标准库提供了once_flag和call_once,就不要多余了。
静态初始化竞争还有一种情况是初始化过程中存在条件竞争:其中一个局部变量声明为静态类型。此变量在声明后已被初始化;对于多线程调用的函数,这意味着有一个条件竞争3354争夺定义这个变量。很多C 11之前的编译器(不支持C 11标准的编译器),实际中确实存在这样的条件竞争,因为在多线程中,每个线程都认为自己是第一个初始化这个变量的线程;或者当一个线程初始化一个变量,而另一个线程想要使用这个变量时,初始化过程还没有完成。在C 11标准中,已经解决了这些问题:初始化和定义都发生在一个线程中,在初始化完成之前,没有其他线程可以处理。条件竞争在初始化阶段结束,比后期处理好很多。如果只需要一个全局实例,这里有一个std:call_once的替代方法。
class my _ class
my_class get_my_class_instance()
{
静态my_class实例;//在C 11中,是线程安全的初始化过程。
返回实例;
}需要读写锁是因为在某些情况下,共享的资源很少被修改,所以如果你仍然使用互斥体进行同步,那么只做读操作的线程仍然需要排队锁,浪费了大量的CPU时间。
读写锁的功能:
当其他线程有写锁时,它们不能读写。当其他线程有读锁时,它们可以读,但不能写。cpp11没有引入读写锁,但是boost库提供了——boost:shared_mutex的共享锁。当任何一个线程有共享锁时,这个线程会试图获取一个独占锁,直到其他线程放弃它们的锁;类似地,当任何线程有一个独占锁时,其他线程不能获得共享锁或独占锁,直到第一个线程放弃它自己的锁。
#包含地图
#包含字符串
#包含互斥体
#包含boost/thread/shared_mutex.hpp
类别dns _ entry
dns_cache类
{
std:map std:string,dns_entry条目;
可变boost:shared _ mutex entry _ mutex;
公共:
DNS _ entry find _ entry(STD:string const domain)常量
{
boost:shared _ lock boost:shared _ mutex lk(entry _ mutex);//1,获取共享锁。其他程序仍然可以调用find_entry并且不会阻塞,但是如果调用update_or_add_entry就会阻塞。
std:map std:string,DNS _ entry:const _ iterator const it=
entries.find(域);
return (it==entries.end())?DNS _ entry():it-second;
}
void update _ or _ add _ entry(STD:string const domain
dns_entry常量dns_details)
{
STD:lock _ guard boost:shared _ mutex lk(entry _ mutex);//2,获取独占锁,其他程序会一直阻塞到更新完成,不管调用find_entry还是update_or_add_entry。
entries[domain]=DNS _ details;
}
};
郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。