Как мне заблокировать wxMutex в одной функции и разблокировать ее в другой?

Я должен реализовать свой собственный класс журналирования для использования в программе с двумя потоками, основным и объединяемым потоком обработки. Я не хочу, чтобы какой-либо поток использовал логгер, пока другой использует его, поэтому я решил использовать wxMutex. Регистратор должен действовать как C ++ ostream с оператором<<, за исключением того, что функция потокового манипулятора (например, std :: endl) будет указывать конец вывода логгера. Я думаю, что мне нужен рекурсивный мьютекс, чтобы тот же поток мог продолжать выводить, когда мьютекс заблокирован.

Проблема (я думаю) состоит в том, что мьютекс не полностью разблокируется, поэтому, когда другой поток пытается вывести на регистратор, он блокируется.

Есть ли что-то в моем коде, что я пропускаю?

class Logger{
private:
std::ostream* out;
wxMutex* mut;
....
public:
template<class T>
Logger& operator<<(T str){ // accept any type of input and lock outputting until finished
if(out){
if(mut->TryLock() == wxMUTEX_BUSY){ // if we didn't get lock
mut->Lock(); // we block
}
if(out){
(*out) << str;
out->flush();
}
//mut->Unlock(); // leave locked until done outputting (use std::endl or similar)
}
return *this;
}

// accept stream manipulators and unlock stream output
Logger& operator<<(std::ostream& (*pf) (std::ostream&)){
if(out){
if(mut->TryLock() == wxMUTEX_BUSY){
mut->Lock();
}
(*out) << pf;
out->flush();
while(mut->Unlock()!= wxMUTEX_UNLOCKED);
}
return *this;
}
};

2

Решение

Если вы беспокоитесь о проблемах с многопоточностью, вы можете вместо этого создать макрос, который гарантирует, что мьютекс будет получен до вывода и освобожден после вывода.

Что-то вроде:

#define LOG(logger, output) \
do { logger.lock(); logger << output; logger.unlock(); } while (0)

Logger my_logger;
int some_integer = 5;
LOG(my_logger, "Hello world!" << some_integer << std::endl);
1

Другие решения

Прежде всего, в wxWidgets 2.9 wxLog сама по себе МТ-безопасна, и вы можете иметь независимые цели журнала для каждого потока, так что, возможно, вы могли бы просто использовать ее вместо написания своей собственной.

Во-вторых, используя TryLock() Подозрительно, если вы хотите иметь возможность повторно заблокировать мьютекс, уже принадлежащий текущему потоку, вы должны использовать wxMUTEX_RECURSIVE при создании мьютекса и просто использовать Lock() тем не менее. Однако лично я считаю, что использование рекурсивных мьютексов является плохой идея, потому что она делает ваш MT-код менее понятным и более сложным для размышления, и это почти всегда катастрофично.

Наконец, вся идея полагаться на кого-то, чтобы позвонить << endl это просто неправильно. Слишком легко забыть сделать это где-нибудь и оставить мьютекс заблокированным, чтобы не допустить продолжения всех остальных потоков. Вы обязательно должны создать прокси-объект, блокирующий мьютекс в его ctor и разблокирующий его в его dtor, и используйте его, чтобы гарантировать, что мьютекс всегда разблокируется в конце оператора, выполняющего регистрацию. Я думаю, что используя эту технику, вы также должны избегать рекурсивных мьютексов.

1

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

if(mut->TryLock() == wxMUTEX_BUSY) // if TryLock() returns wxMUTEX_BUSY another thread is using it.
{
mut->Lock(); // A dead lock situation could be detected here because Lock() also returns an error code.
}

TryLock () обычно пытается получить мьютекс без блокировки. Таким образом, если мьютекс уже занят этим вызовом, это означает, что его использует другой поток.

Вы могли бы взглянуть на эта ссылка от wxMutex который объясняет, как работает каждая функция. Их функция возвращает значения, так что вы можете использовать это, чтобы увидеть, что происходит в вашей программе.

Смотрите документ с их сайта ниже.

wxMutex :: Замок

wxMutexError Lock ()

Блокирует объект мьютекса.

Возвращаемое значение

Один из:

wxMUTEX_NO_ERROR Там не было ошибки.

wxMUTEX_DEAD_LOCK Обнаружена тупиковая ситуация.

0
По вопросам рекламы [email protected]