2012-03-01 13 views
0

私が使用している2つのミューテックスのいずれかで自分の関数がロックを取得できないという問題があります。 VC++ 2010で基本的なデバッグを行い、いくつかのブレークポイントを設定しました。ロックが取得されていればロックされているようです。ミューテックスがロックを取得できません

ミューテックスを使用するコードは、次のとおりである。次にsomwhere他

#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 

をまあ、私は問題を見つけるように見えることはできません。 デバッグした後、私は「力」(質屋抽象マシンから)このコードでロックをaquiringしたい:

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、セル呼び出しますparams)

これは驚きでした。誰かが多分ミスを見ているのでしょうか?

あなたは完全なソースコードが必要な場合、で入手できます。

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

追加情報: PLUGIN_EXPORTブールPLUGIN_CALLロード は、起動時にのみ実行されます。

静的セルAMX_NATIVE_CALLs

ProcessTick(vitrualマシンから呼び出された場合 のみ実行されます) それが拡張で、このいずれかを呼び出して、独自のジョブを完了した後に、アプリケーションのすべてのプロセスのダニを実行されます。

今のところ私はWindows上でのみコードをテストしましたが、Linux上で正常にコンパイルされます。

編集:ポストを短縮するためにLinuxコードを削除しました。私はあなたの最初のスニペットは唯一のいくつかの条件に基づいてミューテックスをアンロック表示されるものと

+3

これは大量のコードです...管理しやすいものに減らすことはできますか?問題を再現できなくなるまで、問題が再現できるだけのコードを送信するまで、コードを削除してみてください。 http://sscce.org/に準拠した例を提供できる場合は、最適です。 – Kiril

+0

私は自分のベストを尽くし、スレッドに関係しないほとんどすべてのものを削除しました。 –

+0

もっといいね! – Kiril

答えて

2

、すなわち擬似コードで、それはのようなものです:私はあなたのコードを理解するため、

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

最初のスニペットは、原則としてロックにして、することができますこの方法決してロックを解除しない

もう1つの潜在的な問題は、コードが最終的に例外的で安全でないことです。あなたは本当にロック/アンロック操作の間に例外が発生しないことを保証できますか?キャッチされていない例外がスローされると、説明したようなデッドロックに陥るからです。私はRAIIのいくつかの並べ替えを使用することをお勧めします。

EDIT:ロック/アンロックを実行する

テストされていないRAII方法:この方法~Lockは常にミューテックスを解放すること

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

注:

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; 
    } 
}; 

使用法は、このようなことができスコープブロックが正常に終了したかどうか、またはキャッチされなかった例外のために、明示的に行ったかどうかにかかわらず、

+0

本当にそれが問題でした。恥のビット私はそれを見ていない。とにかく賞金は22時間で与えることができるので、調整しておいてください。 byTheWay about RAII、私のコードで例を挙げることができますか? –

+0

@Rafal Grasman:答えの編集を参照してください。また、Boostを使ってみることもできます.Boostは、移植性を提供し、独自のコードを記述(およびテスト)することを防ぎます。 – doublep

+0

ああ、今私もそれを理解しています:]ありがとう。 そして、まもなく、私は自分のプロジェクトをブーストで再構築します。 –

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のロックを解除されることはありませんtrueの場合。

+0

ええ、それはあなたが少し早いhehだった前に、私が見る問題のコードです。 –

+0

ええ、彼は本当に速かった、私はすぐに質問を見た。 :) – Tudor

関連する問題