Уничтожение condition_variable во время ожидания - PullRequest
0 голосов
/ 12 сентября 2018

Сначала мой код, чтобы объяснить мое объяснение:

struct Foo {
    std::condition_variable cv;
};
static Foo* foo; // dynamically created object

// Thread1
foo->cv.wait(...);


// Thread2
foo->cv.notify();
delete foo; // thread1 might have not left the wait function yet

Я пытаюсь удалить std::condition_variable, пока он находится в wait.Поэтому, насколько я понимаю, я должен сначала уведомить его, чтобы он оставил его в ожидании рутины, а затем я могу удалить его.Но после вызова notify* я не могу удалить его сразу, потому что он все еще может ждать, потому что ему нужно несколько циклов.Каков общий способ достижения этого?

Ответы [ 2 ]

0 голосов
/ 12 сентября 2018

Вы можете удалить его сразу.

Цитата из стандарта C ++:

~ condition_variable();

Требуется : должно бытьни одна нить не заблокирована на *this.[Примечание: то есть все темы должны быть уведомлены;впоследствии они могут заблокировать блокировку, указанную в wait.Это ослабляет обычные правила, которые требовали бы, чтобы все вызовы wait происходили до уничтожения. Перед уничтожением должно происходить только уведомление о разблокировке wait.

В основном wait функции необходимы для атомарной блокировки и ожидания:

Выполнение notify_one и notify_all должно быть атомарным.Выполнение wait, wait_for и wait_until должно выполняться в трех атомарных частях:

  1. освобождение мьютекса и вход в состояние ожидания;
  2. разблокировка wait
  3. повторное получение блокировки.

Как только notify пробуждает поток, его следует считать "разблокированным" и бороться с мьютексом.


Существуют аналогичные гарантии в отношении std::mutex: потоки не обязаны выходить из unlock до уничтожения мьютекса.

Цитата из стандарта C ++:

Реализацияобеспечивает операции lock и unlock, как описано ниже.В целях определения существования гонки данных они ведут себя как атомарные операции.Операции lock и unlock на одном мьютексе должны выполняться в едином общем порядке.

Позже:

Примечание: после того, как поток A имеетвызываемый unlock(), освобождая мьютекс, другой поток B может заблокировать тот же мьютекс, заметить, что он больше не используется, разблокировать его и уничтожить его до того, как поток A, кажется, вернулся из своегоunlock call .

Такие гарантии необходимы, чтобы избежать таких проблем, как this , когда мьютекс внутри объекта используется для защиты счетчика ссылок на объекты.


Обратите внимание, что это не гарантирует, что ваша реализация не содержит ошибок в этом отношении.В прошлом у glibc было несколько ошибок, связанных с уничтожением объектов синхронизации, в частности pthread_mutex_unlock имел доступ к мьютексу перед возвратом .

0 голосов
/ 12 сентября 2018

Одно простое исправление: переместите delete foo в поток 1 после foo->cv.wait(...);.

Лучшим исправлением было бы изменение дизайна для работы с std::shared_ptr, без ручных delete вызовов.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...