Я использую библиотеку boost :: thread C ++, что в моем случае означает, что я использую pthreads. Официально мьютекс должен быть разблокирован из того же потока, который его блокирует, и я хочу получить эффект блокировки в одном потоке, а затем разблокировки в другом. Есть много способов добиться этого. Одна из возможностей - написать новый класс мьютекса, который допускает такое поведение.
Например:
class inter_thread_mutex{
bool locked;
boost::mutex mx;
boost::condition_variable cv;
public:
void lock(){
boost::unique_lock<boost::mutex> lck(mx);
while(locked) cv.wait(lck);
locked=true;
}
void unlock(){
{
boost::lock_guard<boost::mutex> lck(mx);
if(!locked) error();
locked=false;
}
cv.notify_one();
}
// bool try_lock(); void error(); etc.
}
Я должен указать, что приведенный выше код не гарантирует доступ к FIFO, поскольку, если один поток вызывает lock (), а другой вызывает unlock (), этот первый поток может получить блокировку раньше других ожидающих потоков. (Если задуматься, документация boost :: thread, похоже, не дает никаких явных гарантий планирования для мьютексов или условных переменных). Но давайте пока просто проигнорируем это (и любые другие ошибки).
Мой вопрос: если я решу пойти по этому пути, смогу ли я использовать такой мьютекс в качестве модели для концепции Boost Lockable. Например, что-нибудь пойдет не так, если я использую boost::unique_lock< inter_thread_mutex >
для доступа в стиле RAII, а затем передам эту блокировку boost::condition_variable_any.wait()
и т. Д.
С одной стороны, я не понимаю, почему бы и нет. С другой стороны, «я не понимаю, почему бы и нет» обычно очень плохой способ определить, будет ли что-то работать.
Причина, по которой я спрашиваю, заключается в том, что если окажется, что мне нужно написать классы-оболочки для блокировок RAII, переменных условий и всего остального, тогда я бы предпочел просто найти другой способ достичь того же эффекта.
РЕДАКТИРОВАТЬ: Тип поведения, который я хочу, в основном выглядит следующим образом. У меня есть объект, и его нужно блокировать всякий раз, когда он изменяется. Я хочу заблокировать объект из одного потока и поработать над ним. Затем я хочу, чтобы объект был заблокирован, пока я приказываю другому рабочему потоку завершить работу. Таким образом, первый поток может продолжить и делать что-то еще, пока рабочий поток завершается. Когда рабочий поток завершает работу, он разблокирует мьютекс.
И я хочу, чтобы переход был незаметным, чтобы никто другой не мог установить блокировку мьютекса, когда поток 1 начинает работу, а поток 2 завершает ее.
Что-то вроде inter_thread_mutex, похоже, будет работать, и это также позволит программе взаимодействовать с ним, как если бы это был обычный мьютекс. Так что это похоже на чистое решение. Если есть лучшее решение, я был бы рад услышать и это.
ИЗМЕНИТЬ СНОВА: Причина, по которой мне нужны блокировки для начала, заключается в том, что существует несколько основных потоков, и блокировки предназначены для предотвращения одновременного доступа к общим объектам недопустимыми способами. Таким образом, код уже использует безблокировочную последовательность операций на уровне цикла на уровне главного потока. Кроме того, в исходной реализации не было рабочих потоков, а мьютексы были обычными кошерными мьютексами.
Inter_thread_thingy появился как оптимизация, в первую очередь для улучшения времени отклика. Во многих случаях этого было достаточно, чтобы гарантировать, что «первая часть» операции A произойдет до «первой части» операции B. В качестве глупого примера скажем, что я пробиваю объект 1 и получаю синяк под глазом. Затем я приказываю объекту 1 изменить его внутреннюю структуру, чтобы отразить все повреждения тканей. Я не хочу ждать повреждения ткани, прежде чем перейду к удару по объекту 2. Однако я хочу, чтобы повреждение ткани произошло как часть той же операции; например, тем временем я не хочу, чтобы какой-либо другой поток изменял конфигурацию объекта таким образом, чтобы повреждение ткани стало недопустимой операцией. (да, этот пример во многих отношениях несовершенен, и нет, я не работаю над игрой)
Итак, мы внесли изменение в модель, в которой право собственности на объект может быть передано рабочему потоку для завершения операции, и на самом деле это работает довольно хорошо; каждый главный поток может выполнить гораздо больше операций, потому что ему не нужно ждать их завершения. И поскольку последовательность событий на уровне главного потока по-прежнему основана на циклах, легко написать высокоуровневые операции главного потока, поскольку они могут быть основаны на предположении, что операция завершена (точнее, критический " первая часть ", от которой зависит логика последовательности, завершена), когда возвращается соответствующий вызов функции.
Наконец, я подумал, что было бы неплохо использовать мьютексы / семафоры inter_thread с использованием RAII с блокировками ускорения, чтобы инкапсулировать необходимую синхронизацию, которая требуется для того, чтобы все это работало.
unique_lock
и т. Д. С семафорами, а также с мьютексами. - person Potatoswatter   schedule 03.05.2010