기사 예시를 위한 이 저장소
safe_ptr.h
에는 다음의 C++ 코드가 포함되어 있습니다.
safe_ptr<>
- 함수에 전달되는 경우에도 사용자 정의 개체를 스레드로부터 안전하게 만듭니다.
contention_free_shared_mutex<>
- std::shared_mutex
보다 10배 빠릅니다.
contfree_safe_ptr<>
- 잠금 없는 알고리즘의 속도로 사용자 정의 개체를 스레드로부터 안전하게 만듭니다.
예가 있습니다:
safe_ptr<>
사용 방법 - 기사 1: https://www.codeproject.com/Articles/1183379/We-make-any-object-thread-safecontention_free_shared_mutex<>
사용 방법 - 기사 2: https://www.codeproject.com/Articles/1183423/We-make-a-std-shared-mutex-times-faster벤치마크가 있습니다:
bench_contfree - 벤치마크 경합 없는 공유 뮤텍스 - 기사 2: https://www.codeproject.com/Articles/1183423/We-make-a-std-shared-mutex-times-faster
벤치마크 - 벤치마크 경합 없는 공유 뮤텍스(확장) - 기사 3: https://www.codeproject.com/Articles/1183446/Thread-safe-std-map-with-the-speed-of-lock-free-ma
CDS_test - 경합 없는 공유 뮤텍스로 보호되는 벤치마크 잠금 없는 lib-CDS 및 std::map
- 기사 3: https://www.codeproject.com/Articles/1183446/Thread-safe-std-map-with-the- 잠금 없는 속도-ma
Real_app_bench - 경합 없는 공유 뮤텍스로 보호되는 벤치마크 잠금 없는 lib-CDS 및 std::map
(실제 애플리케이션 시뮬레이션 - 각 스레드 간 데이터 교환 사이에 20usec 지연 추가) - 기사 3: https://www.codeproject.com/Articles/1183446/Thread-safe-std-map-with-the-speed-of -자물쇠 없는 엄마
끌어오기 요청의 경우 별도의 분기를 사용하세요: https://github.com/AlexeyAB/object_threadsafe/tree/for_pull_requests
끌어오기 요청 전에 - CDS_test, Real_app_bench 또는 벤치마크 폴더와 같은 서버 CPU에서 필요한 모든 벤치마크를 실행하고 결과 차트의 이미지를 삽입하십시오.
safe_ptr<>
사용 방법 - std::shared_ptr<>
과 같은 방식: http://coliru.stacked-crooked.com/a/ccf634f1a5e7f991 # include < iostream >
# include < thread >
# include < vector >
# include < string >
# include < map >
# include " safe_ptr.h "
int main () {
sf::safe_ptr< std::map< std::string, int > > safe_map_string_int;
std::thread t1 ([&]() { safe_map_string_int-> emplace ( " apple " , 1 ); });
std::thread t2 ([&]() { safe_map_string_int-> emplace ( " potato " , 2 ); });
t1. join (); t2. join ();
std::cout << " apple = " << (*safe_map_string_int)[ " apple " ] <<
" , potato = " << (*safe_map_string_int)[ " potato " ] << std::endl;
return 0 ;
}
sf::contention_free_shared_mutex
사용 방법 - std::shared_mutex
와 같은 방식: http://coliru.stacked-crooked.com/a/11c191b06aeb5fb6 # include < iostream >
# include < thread >
# include < vector >
# include " safe_ptr.h "
template < typename T>
void func (T &s_m, int &a, int &b)
{
for ( size_t i = 0 ; i < 100000 ; ++i)
{
// x-lock for modification
{
s_m. lock ();
a++;
b++;
s_m. unlock ();
}
// s-lock for reading
{
s_m. lock_shared ();
assert (a == b); // will never happen
s_m. unlock_shared ();
}
}
}
int main () {
int a = 0 ;
int b = 0 ;
sf::contention_free_shared_mutex< > s_m;
// 20 threads
std::vector< std::thread > vec_thread ( 20 );
for ( auto &i : vec_thread) i = std::move ( std::thread ([&]() { func (s_m, a, b); }));
for ( auto &i : vec_thread) i. join ();
std::cout << " a = " << a << " , b = " << b << std::endl;
getchar ();
return 0 ;
}
2.1. contfree_safe_ptr< std::map >
사용 방법 : http://coliru.stacked-crooked.com/a/b78467b7a3885e5b
# include " safe_ptr.h "
sf::contfree_safe_ptr< std::map<std::string, int > > safe_map_strings_global; // cont-free shared-mutex
template < typename T>
void func (sf::contfree_safe_ptr<T> safe_map_strings)
{
// read-only (shared lock during access)
sf::contfree_safe_ptr<T> const &readonly_safe_map_string = safe_map_strings;
for ( size_t i = 0 ; i < 100000 ; ++i)
{
// two Shared locks (recursive)
assert (readonly_safe_map_string-> at ( " apple " ) == readonly_safe_map_string-> at ( " potato " ));
std::lock_guard< decltype (safe_map_strings)> lock (safe_map_strings); // 1-st eXclusive lock
safe_map_strings-> at ( " apple " ) += 1 ; // 2-nd recursive eXclusive lock
safe_map_strings-> find ( " potato " )-> second += 1 ; // 3-rd recursive eXclusive lock
}
}
int main () {
(*safe_map_strings_global)[ " apple " ] = 0 ;
(*safe_map_strings_global)[ " potato " ] = 0 ;
std::vector<std::thread> vec_thread ( 10 );
for ( auto &i : vec_thread) i = std::move ( std::thread ([&]() { func (safe_map_strings_global); }));
for ( auto &i : vec_thread) i. join ();
std::cout << " END: potato is " << safe_map_strings_global-> at ( " potato " ) <<
" , apple is " << safe_map_strings_global-> at ( " apple " ) << std::endl;
return 0 ;
}
contfree_safe_ptr< std::map >
및 safe_obj<>
의 고성능 사용: http://coliru.stacked-crooked.com/a/f7079aa1acc00a78 # include " safe_ptr.h "
using namespace sf ;
struct field_t { int money, time; field_t ( int m, int t) : money(m), time(t) {} field_t () : money( 0 ), time( 0 ) {} };
typedef safe_obj< field_t , spinlock_t > safe_obj_field_t ;
contfree_safe_ptr< std::map< int , safe_obj_field_t > > safe_map_contfree_rowlock_global;
template < typename T>
void benchmark_safe_ptr_rowlock (T safe_map, size_t const iterations_count, size_t const container_size)
{
const unsigned int seed = ( unsigned ) std::chrono::system_clock::now (). time_since_epoch (). count ();
std::default_random_engine generator (seed);
std::uniform_int_distribution< size_t > index_distribution ( 0 , container_size);
enum { insert_op, delete_op, update_op, read_op };
std::uniform_int_distribution< size_t > operation_distribution (insert_op, read_op); // 0 - 4
for ( size_t i = 0 ; i < iterations_count; ++i)
{
int const rnd_index = index_distribution (generator); // 0 - container_size
int const num_op = operation_distribution (generator); // insert_op, update_op, delete_op, read_op
switch (num_op) {
case insert_op: {
slock_safe_ptr (safe_map)-> find (rnd_index); // find for pre-cache to L1 with temprorary S-lock
safe_map-> emplace (rnd_index, ( field_t (rnd_index, rnd_index))); // insert with X-lock on Table
break ;
}
case delete_op: {
slock_safe_ptr (safe_map)-> find (rnd_index); // find for pre-cache to L1 with temprorary S-lock
size_t erased_elements = safe_map-> erase (rnd_index); // erase with X-lock on Table
}
break ;
case update_op: {
auto s_safe_map = slock_safe_ptr (safe_map); // S-lock on Table
auto it = s_safe_map-> find (rnd_index);
if (it != s_safe_map-> cend ()) {
auto x_field = xlock_safe_ptr (it-> second );
x_field-> money += rnd_index; // X-lock on field, still S-lock on Table (must necessarily be)
}
}
break ;
case read_op: {
auto s_safe_map = slock_safe_ptr (safe_map); // S-lock on Table
auto it = s_safe_map-> find (rnd_index);
if (it != s_safe_map-> cend ()) {
auto s_field = slock_safe_ptr (it-> second );
volatile int money = s_field-> money ; // S-lock on field, still S-lock on Table (must be)
// volatile here only to avoid optimization for unused money-variable
}
}
break ;
default : std::cout << " n wrong way! n " ; break ;
}
}
}
int main () {
const size_t iterations_count = 100000 ; // operations of data exchange between threads
const size_t container_size = 100000 ; // elements in container
std::vector<std::thread> vec_thread ( 8 ); // threads number
std::cout << " Threads: " << vec_thread. size () << std::endl;
std::cout << " Testing safe<map,contf>rowlock... n " ;
for ( auto &i : vec_thread) i = std::move ( std::thread ([&]() {
benchmark_safe_ptr_rowlock (safe_map_contfree_rowlock_global, iterations_count, container_size);
}));
for ( auto &i : vec_thread) i. join ();
std::cout << " Successfully completed. " << std::endl;
return 0 ;
}