互斥锁无法获得锁定

时间:2012-03-01 20:29:49

标签: c++ multithreading mutex

我遇到一个问题,我的某个函数无法获取我使用的2个互斥锁之一的锁定。 我在VC ++ 2010中做了一个基本的调试,设置了一些断点,看起来如果锁定被获取,它就会解锁。

使用互斥锁的代码如下:

#define SLEEP(x) { Sleep(x); }
#include<windows.h>

    void Thread::BackgroundCalculator( void *unused ){
    while( true ){
        if(MUTEX_LOCK(&mutex_q, 5) == 1){
            if(!QueueVector.empty()){
//cut
                MUTEX_UNLOCK(&mutex_q);
                    //cut
                while(MUTEX_LOCK(&mutex_p,90000) != 1){}
                //cut
                MUTEX_UNLOCK(&mutex_p);
            }

        }
        SLEEP(25);
    }
}

然后在其他地方:

PLUGIN_EXPORT void PLUGIN_CALL
    ProcessTick(){
    if(g_Ticked == g_TickMax){
        if(MUTEX_LOCK(&mutex_p, 1) == 1){
            if(!PassVector.empty()){
                PassVector.pop();
            }
            MUTEX_UNLOCK(&mutex_p);
        }
        g_Ticked = -1;
    }
    g_Ticked += 1;
}

static cell AMX_NATIVE_CALL n_CalculatePath( AMX* amx, cell* params ){
    if(MUTEX_LOCK(&mutex_q,1) == 1){
        QueueVector.push_back(QuedData(params[1],params[2],params[3],amx));
        MUTEX_UNLOCK(&mutex_q);
        return 1;
    }
    return 0;
}

INIT:

PLUGIN_EXPORT bool PLUGIN_CALL Load( void **ppData ) {
    MUTEX_INIT(&mutex_q);
    MUTEX_INIT(&mutex_p);
    START_THREAD( Thread::BackgroundCalculator, 0);
    return true;
}

一些变量和功能:

int MUTEX_INIT(MUTEX *mutex){
    *mutex = CreateMutex(0, FALSE, 0);
    return (*mutex==0);
}

int MUTEX_LOCK(MUTEX *mutex, int Timex = -1){
    if(WaitForSingleObject(*mutex, Timex) == WAIT_OBJECT_0){
        return 1;
    }
    return 0;
}
int MUTEX_UNLOCK(MUTEX *mutex){
    return ReleaseMutex(*mutex);
}

MUTEX mutex_q = NULL;
MUTEX mutex_p = NULL;

并定义:

#   include <process.h>
#   define OS_WINDOWS
#   define MUTEX HANDLE
#   include <Windows.h>
#   define EXIT_THREAD() { _endthread(); }
#   define START_THREAD(a, b) { _beginthread( a, 0, (void *)( b ) ); }

线程头文件:

#ifndef __THREAD_H
#define __THREAD_H

class Thread{
    public:
                                    Thread                      ( void );
                                   ~Thread                      ( void );
    static void                     BackgroundCalculator        ( void *unused );

};

#endif

好吧,我似乎无法找到问题。 在调试之后,我想通过这个代码(来自pawn抽象机器)“强制”获取锁定:

if (strcmp("/routeme", cmdtext, true) == 0){
    new fromnode = NearestPlayerNode(playerid);
    new start = GetTickCount();
    while(CalculatePath(fromnode,14,playerid+100) == 0){
        printf("0 %d",fromnode);
    }
    printf("1 %d",fromnode);
    printf("Time: %d",GetTickCount()-start);
    return 1;
}

但它继续无休止,CalculatePath调用静态单元格AMX_NATIVE_CALL n_CalculatePath(AMX * amx,cell * params)

这有点令人惊讶。有没有人可能会看到错误?

如果您需要完整的源代码,请访问:

http://gpb.googlecode.com/files/RouteConnector_174alpha.zip

额外信息: PLUGIN_EXPORT bool PLUGIN_CALL加载 只在启动时执行。

静态单元格AMX_NATIVE_CALLs 仅在从玻璃机器调用时才执行

ProcessTick() 得到应用程序的每个进程滴答,在它完成自己的工作后,它会在扩展中调用它。

现在我只测试了windows上的代码,但它在linux上编译得很好。

编辑:删除linux代码以缩短帖子。

2 个答案:

答案 0 :(得分:2)

从我看到你的第一个代码片段仅基于某些条件解锁互斥锁,即在伪代码中它就像:

mutex.lock ():
if some_unrelated_thing:
    mutex.unlock ()

据我了解您的代码,这样第一个代码段原则上可以锁定,然后永远不会解锁。

另一个潜在的问题是您的代码最终是异常不安全的。您真的能保证锁定/解锁操作之间不会发生异常吗?因为如果抛出任何未捕获的异常,就会陷入如上所述的死锁。我建议在这里使用某种RAII。

修改

未经测试的RAII执行锁定/解锁的方式:

struct Lock
{
  MUTEX&  mutex;
  bool    locked;

  Lock (MUTEX& mutex)
    : mutex (mutex),
      locked (false)
  { }

  ~Lock ()
  { release (); }

  bool acquire (int timeout = -1)
  {
    if (!locked && WaitForSingleObject (mutex, timeout) == WAIT_OBJECT_0)
      locked = true;
    return locked;
  }

  int release ()
  {
    if (locked)
      locked = ReleaseMutex (mutex);
    return !locked;
  }
};

用法可能是这样的:

{
  Lock  q (mutex_q);
  if (q.acquire (5)) {
      if (!QueueVector.empty ()) {
          q.release ();
          ...
      }
  }
}

请注意,这种方式~Lock始终会释放互斥锁,无论您是否明确地执行了此操作,范围块是正常退出还是由于未捕获的异常。

答案 1 :(得分:2)

我不确定这是否是预期的行为,但在此代码中:

void Thread::BackgroundCalculator( void *unused ){
while( true ){
    if(MUTEX_LOCK(&mutex_q, 5) == 1){
        if(!QueueVector.empty()){
            //cut
            MUTEX_UNLOCK(&mutex_q);
            //cut
            while(MUTEX_LOCK(&mutex_p,90000) != 1){}
            //cut
            MUTEX_UNLOCK(&mutex_p);
        }
    }
    SLEEP(25);
}

如果QueueVector.empty为真,则永远不会解锁mutex_q