2013-05-01 57 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