Repositori ini untuk contoh artikel
safe_ptr.h
berisi kode C++:
safe_ptr<>
- menjadikan objek khusus Anda aman untuk thread, bahkan ketika diteruskan ke suatu fungsi
contention_free_shared_mutex<>
- 10 X kali lebih cepat dari std::shared_mutex
contfree_safe_ptr<>
- jadikan objek kustom Anda aman dengan kecepatan algoritme bebas kunci
Ada contohnya:
safe_ptr<>
- Artikel 1: https://www.codeproject.com/Articles/1183379/We-make-any-object-thread-safecontention_free_shared_mutex<>
- Artikel 2: https://www.codeproject.com/Articles/1183423/We-make-a-std-shared-mutex-times-fasterAda tolok ukurnya:
bench_contfree - Tolok ukur mutex gratis bersama - Artikel 2: https://www.codeproject.com/Articles/1183423/We-make-a-std-shared-mutex-times-faster
benchmark - Tolok ukur mutex bersama gratis (diperpanjang) - Artikel 3: https://www.codeproject.com/Articles/1183446/Thread-safe-std-map-with-the-speed-of-lock-free-ma
CDS_test - lib-CDS dan std::map
bebas kunci patokan dijaga oleh mutex bersama bebas konten - Artikel 3: https://www.codeproject.com/Articles/1183446/Thread-safe-std-map-with-the- kecepatan-kunci-bebas-ma
Real_app_bench - lib-CDS dan std::map
bebas kunci benchmark yang dijaga oleh mutex bersama bebas perselisihan
(Mensimulasikan aplikasi nyata - menambahkan 20 penundaan usec antara setiap pertukaran data antar-thread) - Artikel 3: https://www.codeproject.com/Articles/1183446/Thread-safe-std-map-with-the-speed-of -bebas-kunci-ma
Untuk Permintaan Tarik Anda, gunakan cabang terpisah: https://github.com/AlexeyAB/object_threadsafe/tree/for_pull_requests
Sebelum Permintaan Tarik - jalankan semua benchmark yang diperlukan, sebaiknya di CPU server, seperti di folder: CDS_test, Real_app_bench atau benchmark - dan masukkan gambar grafik hasil.
safe_ptr<>
- dengan cara yang sama seperti 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
- dengan cara yang sama seperti 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. Cara menggunakan 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 >
dan safe_obj<>
berperforma tinggi : 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 ;
}