2013-05-01 70 views
0

我正在學習關鍵部分(爲了多線程的目的),並且我在網上找到了一個使用它的類。我不明白爲什麼我的代碼無法正常工作 - 我應該在控制檯顯示屏上獲得「成功」,但我不知道。嵌套鎖(關鍵部分)不工作

我鎖定不正確嗎?我確信我正在準確地進入和退出這些部分 - 但我不知道爲什麼第三個線程(mul)似乎不起作用。

這裏是主代碼(在VS 2012做這個):

#include "stdafx.h" 
#include <windows.h> 
#include <process.h> 
#include <iostream> 
#include <assert.h> 
#include <queue> 
#include "Lock.h" 

//File: CriticalSectionExample.cpp 

#define MAX_THREADS 2 

using namespace std; 

static unsigned int counter = 100; 
static bool alive = true; 
static examples::Lock lock_1; 
static examples::Lock lock_2; 

queue<int> test_q; 
queue<int> later_q; 

static unsigned __stdcall sub(void *args) 
{ 
    while(alive) 
    { 
     cout << "tq"; 
     lock_1.acquire(); 
     test_q.push(1); 
     lock_1.release(); 

     ::Sleep(500); 
    } 
    return 0; 
} 

static unsigned __stdcall add(void *args) 
{ 
    while(alive) 
    { 
     if (!test_q.empty()) 
     { 
      int first = test_q.front(); 
      //cout << first << endl; 

      lock_1.acquire(); 
      test_q.pop(); 
      lock_1.release(); 

      lock_2.acquire(); 
      cout << "lq" << first << endl; 
      later_q.push(first); 
      lock_2.release(); 
     } 

     ::Sleep(500); 
    } 
    return 0; 
} 

static unsigned __stdcall mul(void *args) 
{ 
    while(alive) 
    { 
     if (!later_q.empty()) 
     { 
      cout << "success" << endl; 
      lock_2.acquire(); 
      test_q.pop(); 
      lock_2.release(); 
     } 

     ::Sleep(500); 
    } 
    return 0; 
} 

int main() 
{ 
    // create threads 
    unsigned tadd; 
    HANDLE hadd = (HANDLE) ::_beginthreadex(0, 0, &add, 0, CREATE_SUSPENDED, &tadd); 
    assert(hadd != 0); 

    unsigned tsub; 
    HANDLE hsub = (HANDLE) ::_beginthreadex(0, 0, &sub, 0, CREATE_SUSPENDED, &tsub); 
    assert(hsub != 0); 

    unsigned tmul; 
    HANDLE hmul = (HANDLE) ::_beginthreadex(0, 0, &mul, 0, CREATE_SUSPENDED, &tsub); 
    assert(hmul != 0); 

    // start threads 
    ::ResumeThread(hadd); 
    ::ResumeThread(hsub); 

    ::Sleep(10000); // let threads run for 10 seconds 

    // stop & cleanup threads 
    alive = false; 
    ::WaitForSingleObject(hsub, INFINITE); 
    ::CloseHandle(hsub); 
    ::WaitForSingleObject(hadd, INFINITE); 
    ::CloseHandle(hadd); 

    return 0; 
} 

,這是包括關鍵節的頭文件:

#ifndef _Lock_H_ 
#define _Lock_H_ 


#include <windows.h> 

/** 
*@description: A simple Lock implementation using windows critical section object 
*/ 

namespace examples 
{ 
    class Lock 
    { 
    public: 
     Lock() 
     { 
      ::InitializeCriticalSection(&m_cs); 
     } 

     ~Lock() 
     { 
      ::DeleteCriticalSection(&m_cs); 
     } 

     void acquire() 
     { 
      ::EnterCriticalSection(&m_cs); 
     } 

     void release() 
     { 
      ::LeaveCriticalSection(&m_cs); 
     } 

    private: 
     Lock(const Lock&); 
     Lock& operator=(const Lock&); 

     CRITICAL_SECTION m_cs; 
    }; 

} 

#endif //_Lock_H_ 

回答

2

看來你忘了恢復你的第三個線。

我想說你的代碼有幾個潛在的缺陷。我建議你鎖定你使用共享變量的每個地方(是的,即使你只讀取了它們的值)。這一次它可能工作,但有時甚至讀取正在被其他線程修改的對象可能是危險的。

您也可以申請多一點複雜的自由/鎖定模式,以你的代碼,這樣你就不需要調用獲取/釋放手動

class AutoLock 
{ 
public: 
    AutoLock(Lock& l) 
    :lock(l) 
    { 
     lock.acquire(); 
    } 

    ~AutoLock() 
    { 
     lock.release(); 
    } 

    Lock& lock; 
}; 

然後你可以重寫你的功能,使它們更清潔,更安全:

static unsigned __stdcall sub(void *args) 
{ 
    while(alive) 
    { 
     cout << "tq"; 
     { 
      examples::AutoLock lock(lock_1); 
      test_q.push(1); 
     } 
     ::Sleep(500); 
    } 
    return 0; 
} 

需要注意的是獨立的範圍是必需的,因爲否則的關鍵部分lock_1將被鎖定,直到::睡眠執行這不是通常要什麼(500)。

+0

謝謝你。但是在VS2012上,有一個與'AutoLock(Lock&l)'有關的錯誤 - 它一直告訴我它期望有一個')'。那有什麼問題?它適用於VS2010,但不適用於2012. – sccs 2013-05-03 07:21:39

+0

也許你試圖在Lock聲明之上聲明類AutoLock。在這種情況下,編譯器不知道Lock是什麼,因此期望別的東西。如果這不是問題複製錯誤在這裏,也許與編譯日誌首先發生此錯誤。 – Bogolt 2013-05-03 08:17:50

+0

我做了愚蠢的事情(並且把'l'看作'1'),這就是問題所在。非常感謝你! – sccs 2013-05-03 08:26:21