не может получить блокировку r / w на std :: map среди boost :: thread s? - PullRequest
0 голосов
/ 19 февраля 2019

Я хочу добиться блокировки ar / w на std :: map, которая используется несколькими потоками.Сначала я обернул std :: map и взял boost :: shared_mutex в качестве члена класса и обернул операции вставки / стирания / [] для обеспечения безопасности потока.

Я использовал boost :: shared_lock и boost :: unique_lock для r/ w синхронизация.

Я могу вспомнить другой дизайн, где может быть создан поток чтения / записи, который будет работать исключительно на std :: map, но я подумал о способе, которым я блокирую / разблокирую чтение или записьфункции std :: map.дело в том, что я не достигаю синхронизации.

что мне здесь не хватает?я должен изменить дизайн?если да ... можете ли вы объяснить, почему этот дизайн не будет работать?

здесь приведена реализация блокировки ar / w https://coliru.stacked -crooked.com / a / 8a96d27cb0a3e60c

еще одно ускорение :: реализация мьютекса https://coliru.stacked -crooked.com / a / 717c26ee1917760a

для справки:

#include <unistd.h>
#include <map>
#include <vector>
#include <iostream>
#include <pthread.h>
#include <boost/thread/thread.hpp>
#include <boost/thread/locks.hpp>
#include <boost/thread/shared_mutex.hpp>

std::string gen_random(const int len) {
    char gen_s[100];
    static const char charset[] =
        "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
        "abcdefghijklmnopqrstuvwxyz";

    for (int i = 0; i < len; ++i) {
        gen_s[i] = charset[rand() % (sizeof(charset) - 1)];
    }

    gen_s[len] = 0;
    std::string s = gen_s;
    return s;
}
const int ITERS = 100;

template <typename T1, typename T2>
class ThreadSafeMap
{

private:
    std::map<T1, T2> _map;
    boost::shared_mutex _lockShared;
    //boost::mutex _lock;
  public:
    ThreadSafeMap();

    bool insert(std::pair<T1, T2> kv);
    typename std::map<T1, T2>::const_iterator find(T1 k);
    bool erase(T1 k);
    T2 at(int index);
    typename std::map<T1, T2>::iterator end();
    typename std::map<T1, T2>::iterator begin();
    T2& operator[](const T1& k);
    //void operator=(T2 v);
};

template <typename T1, typename T2>
ThreadSafeMap<T1, T2>::ThreadSafeMap()
{
}

template <typename T1, typename T2>
bool ThreadSafeMap<T1, T2>::insert(std::pair<T1, T2> kv)
{
    boost::unique_lock<boost::shared_mutex> _wrLock(this->_lockShared);
    _map.insert(kv);
    return true;
}

template <typename T1, typename T2>
typename std::map<T1, T2>::const_iterator ThreadSafeMap<T1, T2>::find(T1 k)
{

    boost::shared_lock<boost::shared_mutex> _rdLock(this->_lockShared);
    typename std::map<T1, T2>::const_iterator toReturn = _map.find(k);
    return toReturn;
}

template <typename T1, typename T2>
bool ThreadSafeMap<T1, T2>::erase(T1 data)
{

    boost::unique_lock<boost::shared_mutex> _wrLock(this->_lockShared);
    _map.erase(data);
    return true;
}

template <typename T1, typename T2>
T2 ThreadSafeMap<T1, T2>::at(int index)
{
    boost::shared_lock<boost::shared_mutex> _rdLock(this->_lockShared); 
    T2 toReturn = _map.at(index);
    return toReturn;
}

template <typename T1, typename T2>
typename std::map<T1, T2>::iterator ThreadSafeMap<T1, T2>::end()
{
    boost::shared_lock<boost::shared_mutex> _rdLock(this->_lockShared);
    typename std::map<T1, T2>::iterator toReturn = _map.end();
    return toReturn;
}

template <typename T1, typename T2>
typename std::map<T1, T2>::iterator ThreadSafeMap<T1, T2>::begin()
{
    boost::shared_lock<boost::shared_mutex> _rdLock(this->_lockShared);
    typename std::map<T1, T2>::iterator toReturn = _map.begin();
    return toReturn;
}

template <typename T1, typename T2>
T2& ThreadSafeMap<T1, T2>::operator[](const T1& k)
{

    boost::unique_lock<boost::shared_mutex> _wrLock(this->_lockShared);
    T2& toReturn =  _map[k];
    return toReturn;
}


ThreadSafeMap<std::string,std::string> mapp;

void writer(int threadNo)
{
    while(true)
    {   
        std::string key = gen_random(10);
        std::string value = gen_random(10);
        std::cout << threadNo << " putting " << key << ":" << value << std::endl; 
        mapp[key] = value;
        usleep(100);
    }

}

void reader(int threadNo)
{

    while(true)
    {
        //std::map<std::string,std::string>::iterator it =  mapp.begin();
        std::string str;
        if(mapp.begin() != mapp.end())
        {
            str = mapp.begin()->first;
            std::cout << threadNo << " retrieved " << mapp.begin()->first << ":" << mapp.begin()->second << std::endl;
            mapp.erase(str);
            std::cout << threadNo << " erased " << str << std::endl;

        }
        //std::string str1 = it->first;
        //mapp.erase(it->first);
        //std::cout << threadNo << " erased " << it->first << std::endl;
        usleep(100);
    }
}

int main(int argc, char* argv[])
{
    int n = 10; 
    std::vector<boost::thread> allThreadVector;
    while(n--)
    {
        boost::thread t1 = boost::thread(&reader, 10-n);
        boost::thread t2 = boost::thread(&writer,10-n);
        allThreadVector.push_back(std::move(t1));
        allThreadVector.push_back(std::move(t2));
    }
    for (boost::thread &th : allThreadVector)
    {
        // If thread Object is Joinable then Join that thread.
        if (th.joinable())
        {
            std::cout << "joined : " << th.get_id();
            th.join();
        }
    }
    return 0;
}

оба эти способа генерируют данныегонки.

это один из результатов гонки данных:

1 putting nWlrBbmQBh:CDarzOwKkY

1 retrieved nWlrBbmQBh:CDarzOwKkY1 putting HIDdqSCDXr:JmOWFrxsjy

2 retrieved nWlrBbmQBh:CDarzOwKkY

2 erased nWlrBbmQBh

21 retrieved  putting BldbEFSArC:BynEcdyGgx

==================

WARNING: ThreadSanitizer: data race (pid=23638)

  Read of size 8 at 0x7b1800000050 by thread T1:

    #0 fwrite ../../.././libsanitizer/sanitizer_common/sanitizer_common_interceptors.inc:1048 (libtsan.so.0+0x31a18)

    #1 std::basic_streambuf<char, std::char_traits<char> >::sputn(char const*, long) /root/orig/gcc-8.2.0/x86_64-pc-linux-gnu/libstdc++-v3/include/streambuf:458 (libstdc++.so.6+0x10ccc3)

    #2 void std::__ostream_write<char, std::char_traits<char> >(std::basic_ostream<char, std::char_traits<char> >&, char const*, long) /root/orig/gcc-8.2.0/x86_64-pc-linux-gnu/libstdc++-v3/include/bits/ostream_insert.h:50 (libstdc++.so.6+0x10ccc3)

    #3 std::basic_ostream<char, std::char_traits<char> >& std::__ostream_insert<char, std::char_traits<char> >(std::basic_ostream<char, std::char_traits<char> >&, char const*, long) /root/orig/gcc-8.2.0/x86_64-pc-linux-gnu/libstdc++-v3/include/bits/ostream_insert.h:101 (libstdc++.so.6+0x10ccc3)

    #4 void boost::_bi::list1<boost::_bi::value<int> >::operator()<void (*)(int), boost::_bi::list0>(boost::_bi::type<void>, void (*&)(int), boost::_bi::list0&, int) /usr/local/include/boost/bind/bind.hpp:259 (a+0x413a2b)

    #5 boost::_bi::bind_t<void, void (*)(int), boost::_bi::list1<boost::_bi::value<int> > >::operator()() /usr/local/include/boost/bind/bind.hpp:1294 (a+0x4136ab)

    #6 boost::detail::thread_data<boost::_bi::bind_t<void, void (*)(int), boost::_bi::list1<boost::_bi::value<int> > > >::run() /usr/local/include/boost/thread/detail/thread.hpp:116 (a+0x4132e2)

    #7 thread_proxy <null> (libboost_thread.so.1.66.0+0x124fc)


  Previous write of size 8 at 0x7b1800000050 by thread T2:

    #0 memcpy ../../.././libsanitizer/sanitizer_common/sanitizer_common_interceptors.inc:737 (libtsan.so.0+0x308f5)

    #1 std::char_traits<char>::copy(char*, char const*, unsigned long) /root/orig/gcc-8.2.0/x86_64-pc-linux-gnu/libstdc++-v3/include/bits/char_traits.h:350 (libstdc++.so.6+0x11ced1)

    #2 std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::_S_copy(char*, char const*, unsigned long) /root/orig/gcc-8.2.0/x86_64-pc-linux-gnu/libstdc++-v3/include/bits/basic_string.h:340 (libstdc++.so.6+0x11ced1)

    #3 std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::_M_assign(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&) /root/orig/gcc-8.2.0/x86_64-pc-linux-gnu/libstdc++-v3/include/bits/basic_string.tcc:272 (libstdc++.so.6+0x11ced1)

    #4 void boost::_bi::list1<boost::_bi::value<int> >::operator()<void (*)(int), boost::_bi::list0>(boost::_bi::type<void>, void (*&)(int), boost::_bi::list0&, int) /usr/local/include/boost/bind/bind.hpp:259 (a+0x413a2b)

    #5 boost::_bi::bind_t<void, void (*)(int), boost::_bi::list1<boost::_bi::value<int> > >::operator()() /usr/local/include/boost/bind/bind.hpp:1294 (a+0x4136ab)

    #6 boost::detail::thread_data<boost::_bi::bind_t<void, void (*)(int), boost::_bi::list1<boost::_bi::value<int> > > >::run() /usr/local/include/boost/thread/detail/thread.hpp:116 (a+0x4132e2)

    #7 thread_proxy <null> (libboost_thread.so.1.66.0+0x124fc)


  Thread T1 (tid=23640, running) created by main thread at:

    #0 pthread_create ../../.././libsanitizer/tsan/tsan_interceptors.cc:915 (libtsan.so.0+0x2af6b)

    #1 boost::thread::start_thread_noexcept() <null> (libboost_thread.so.1.66.0+0x11879)

    #2 boost::thread::thread<void (*)(int), int>(void (*)(int), int, boost::disable_if<boost::thread_detail::is_convertible<void (*&)(int), boost::thread_attributes>, boost::thread::dummy*>::type) /usr/local/include/boost/thread/detail/thread.hpp:401 (a+0x40c163)

    #3 main /tmp/1550569011.2128205/main.cpp:155 (a+0x40685a)


  Thread T2 (tid=23641, running) created by main thread at:

    #0 pthread_create ../../.././libsanitizer/tsan/tsan_interceptors.cc:915 (libtsan.so.0+0x2af6b)

    #1 boost::thread::start_thread_noexcept() <null> (libboost_thread.so.1.66.0+0x11879)

    #2 boost::thread::thread<void (*)(int), int>(void (*)(int), int, boost::disable_if<boost::thread_detail::is_convertible<void (*&)(int), boost::thread_attributes>, boost::thread::dummy*>::type) /usr/local/include/boost/thread/detail/thread.hpp:401 (a+0x40c163)

    #3 main /tmp/1550569011.2128205/main.cpp:156 (a+0x40687a)


SUMMARY: ThreadSanitizer: data race /root/orig/gcc-8.2.0/x86_64-pc-linux-gnu/libstdc++-v3/include/streambuf:458 in std::basic_streambuf<char, std::char_traits<char> >::sputn(char const*, long)

==================
  • я изменил код итератора, предложенный BJ
  • Я включил r /w код для будущей ссылки, предложенной в комментарии.
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...