Страницы

Поиск по вопросам

пятница, 10 января 2020 г.

Объясните в чем причина deadlock-а?

#cpp #многопоточность #cpp11


Нашел на хабре пример deadlock-а:

template 
class container 
{
     std::mutex _lock;
     std::vector _elements;
public:
     void add(T element) 
     {
          _lock.lock();
          _elements.push_back(element);
          _lock.unlock();
     } 
 void addrange(int num, ...)
 {
      va_list arguments;
      va_start(arguments, num);
      for (int i = 0; i < num; i++)
      {
           _lock.lock();
           add(va_arg(arguments, T));
           _lock.unlock();
      }
      va_end(arguments); 
 }
 void dump()
 {
      _lock.lock();
      for(auto e: _elements)
      std::cout << e << std::endl;
      _lock.unlock();
 }
};

void threadFunction(container &c)
{
     c.addrange(3, rand(), rand(), rand());
}

int main()
{
 srand((unsigned int)time(0));
 container cntr;
 std::thread t1(threadFunction, std::ref(cntr));
 std::thread t2(threadFunction, std::ref(cntr));
 std::thread t3(threadFunction, std::ref(cntr));
 t1.join();
 t2.join();
 t3.join();
 cntr.dump();
 return 0;
}


Правильно ли я понимаю, что дедлок возникает из-за того что в одном и том же потоке
вызывается addrange в котором сначала идет _lock.lock() а затем add в которой опять
идет _lock.lock()? если да, то почему в следующем примере нету дедлока(слегка измененный
в худшую сторону пример из книги Энтони Уильямса, где я специально unlock() не сделал):

struct Y {
private:
mutable std::mutex m;
int data;
int get_data() const {
    m.lock();
    return data;
}

public:
Y(int&& data_) : data(std::move(data_)) {}
friend bool operator==(Y const& lhs, Y const& rhs) {
    if(&lhs==&rhs)
        return true;
    auto lhs_ = lhs.get_data();
    auto rhs_ = rhs.get_data();
    return (lhs_==rhs_);
}
};

int main() {
    Y y1(1); Y y2(2);
    std::cout<<(y1==y2)<


Ответы

Ответ 1



По стандарту поведение для повторного вызова std::mutex::lock в одном потоке для одного и того же std::mutex не определено: If lock is called by a thread that already owns the mutex, the behavior is undefined: for example, the program may deadlock. В том числе, может возникнуть deadlock. В конкретной реализации, например в VS2015, в этом случае возникает исключение. Ваш второй пример вызывает метод std::mutex::lock у разных объектов std::mutex, поэтому описанный выше эффект не возникает.

Комментариев нет:

Отправить комментарий