Я изучаю Critical Section (для целей многопоточности) и нашел онлайн-класс, использующий его. Я не понимаю, почему мой код не работает, хотя я должен получить «успех» на дисплее консоли, но я этого не делаю.
Я неправильно его блокирую? Я уверен, что я вхожу и выходить из разделов точно — но я не знаю, почему третий поток (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_
Кажется, вы забыли возобновить свою третью ветку.
Я хотел бы сказать, что в вашем коде есть несколько потенциальных недостатков. Я бы порекомендовал вам блокировать каждое место, где вы работаете с общими переменными (да, даже если вы только читаете их значение). На этот раз это может сработать, но иногда даже чтение объекта, который изменяется другим потоком, может быть опасным.
Также вы можете применить немного более сложный шаблон Free / Lock к вашему коду, чтобы вам не нужно было вызывать / отпускать вручную
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), а это не то, что вы обычно хотите.
Других решений пока нет …