我应该如何在一个函数中锁定wxMutex并在另一个函数中解锁?

时间:2012-10-10 23:52:52

标签: c++ multithreading thread-safety wxwidgets mutex

我应该实现我自己的日志类,以便在具有两个线程的程序中使用,主线程和可连接的处理线程。我不希望任何一个线程使用记录器而另一个使用它,所以我想我会使用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;
    }
};

3 个答案:

答案 0 :(得分:1)

如果您担心线程问题,可以改为创建一个宏来确保在输出之前获取互斥锁并在输出之后释放。

类似的东西:

#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 :(得分:1)

首先,在wxWidgets中,2.9 wxLog本身是MT安全的,你可以为每个线程设置独立的日志目标,所以也许你可以使用它而不是编写自己的。

其次,使用TryLock()是可疑的,如果您希望能够重新锁定已经属于当前线程的互斥锁,则应在创建互斥锁时使用wxMUTEX_RECURSIVE并使用{{尽管如此。但是我个人认为使用递归互斥体是一个的想法,因为它使你的MT代码不那么清晰,更难以推理,这几乎总是灾难性的。

最后,依赖某人致电Lock()的整个想法是错误的。很容易忘记在某个地方执行此操作并保持互斥锁被锁定以防止所有其他线程继续。您绝对应该创建一个代理对象来锁定其ctor中的互斥锁并在其dtor中解锁它并使用它来确保在执行日志记录的语句结束时始终解锁互斥锁。我认为通过使用这种技术,你应该避免使用递归互斥锁。

答案 2 :(得分:0)

我可能错了,但在我看来你正在试图锁定互斥锁时已经使用了。

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()通常尝试在不阻塞的情况下获取互斥锁。因此,如果互斥锁已经忙于该调用,则意味着另一个线程正在使用它。

您可以查看this link from wxMutex,了解每个功能的工作原理。它们的函数返回值,因此您可以使用它来查看程序中出错的地方。

请参阅下面网站上的文档。

  

wxMutex :: Lock

     

wxMutexError Lock()

     

锁定互斥锁对象。

     

返回值

     

其中一个:

     

wxMUTEX_NO_ERROR 没有错误。

     

wxMUTEX_DEAD_LOCK 检测到死锁情况。