我正在学习临界区(用于多线程),我在网上找到了一个使用它的类(class)。我不明白为什么我的代码不起作用 - 我应该在控制台显示上显示“成功”,但我没有。
我锁定不正确吗?我确定我正在准确地进入和退出这些部分 - 但我不知道为什么第三个线程 (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_
最佳答案
您似乎忘记了恢复您的第三个线程。
我想说您的代码中存在几个潜在的缺陷。我建议您锁定每个使用共享变量的地方(是的,即使您只读取它们的值)。这次它可能会起作用,但有时即使读取正在被其他线程修改的对象也可能很危险。
您还可以将更复杂的释放/锁定模式应用于您的代码,因此您无需手动调用获取/释放
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 将被锁定,直到::Sleep(500) 执行,这不是您通常想要的。
关于c++ - 嵌套锁(关键部分)不起作用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16320436/