Страницы

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

четверг, 21 февраля 2019 г.

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

Нашел на хабре пример 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)<Тут тоже идет два раза подряд вызов get_data() где делается lock() без unlock(), однако программа не виснет, как в первом случае а все отрабатывает на ура


Ответ

По стандарту поведение для повторного вызова 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, поэтому описанный выше эффект не возникает.

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

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