私たちのプロジェクトでは、OS (Linux、Android、OSX、WIN) ごとにOS依存の抽象化 (ファイル、ソケット、スレッドなど) を実装する必要があります。OS の抽象化を実装するための一般的な iter は次のとおりです。
- 各OSに共通のメソッドを定義するOS非依存のクラスヘッダを書く(Cond)。
- os 関数を使用してos依存の実装を記述します (例: pthread_cond、win32 ConditionVariable)。
- cmake を介してリンクおよびビルドします。
Windows で条件変数を実装する際に問題が発生しました。Windows の ConditionVariable はクリティカル セクションで機能するため、Mutex クラスで CriticalSection 関数をラップする必要があります。もちろん、私はposixシステムで標準のposixソリューションを使用しています。
コードは次のとおりです。
1.a) ヘッダー (Linux) - Cond.h
#pragma once
#include <pthread.h>
#include "Types.h"
#include "Mutex.h"
#include "OS.h"
Class Cond
{
public:
Cond();
~Cond();
void signal();
void wait(Mutex& mutex);
private:
pthread_cond_t m_cond;
};
1.b ) ヘッダー (勝利) - Cond.h
#pragam once
#include <windows.h>
#include "Types.h"
#include "Mutex.h"
#include "OS.h"
class Cond
{
public:
Cond();
~Cond();
void signal();
void wait(Mutex& mutex);
private:
CONDITION_VARIABLE m_cond;
};
ご覧のとおり、インターフェイスは共通ですが、型が異なります。
2.a) 実装 (Linux) - Cond.cpp
#include "Cond.h"
//-----------------------------------------------------------------------------
Cond::Cond()
{
memset(&m_cond, 0, sizeof(pthread_cond_t));
pthread_cond_init(&m_cond, NULL);
}
//-----------------------------------------------------------------------------
Cond::~Cond()
{
pthread_cond_destroy(&m_cond);
}
//-----------------------------------------------------------------------------
void Cond::signal()
{
pthread_cond_signal(&m_cond);
}
//-----------------------------------------------------------------------------
void Cond::wait(Mutex& mutex)
{
pthread_cond_wait(&m_cond, &(mutex.m_mutex));
}
条件変数の Linux 実装はうまく機能します。
2.b) 実装 (勝利) - Cond.cpp
#include "Cond.h"
Cond::Cond()
{
InitializeConditionVariable(&m_cond);
}
Cond::~Cond()
{
}
void Cond::signal()
{
WakeConditionVariable(&m_cond);
}
void Cond::wait(Mutex& mutex)
{
CRITICAL_SECTION cs = mutex.handle(); // returns CRITICAL_SECTION
SleepConditionVariableCS(&m_cond, &cs, INFINITE);
}
この実装はコンパイルされますが、機能しません (デッドロック)。
Linux で動作し、Win では動作しない例を次に示します。
void ResourceManager::flush()
{
check_load_queue();
while (true)
{
// Wait for all the resources to be loaded
// by the background thread
m_loading_mutex.lock();
while (m_loading_queue.size() > 0)
{
m_all_loaded.wait(m_loading_mutex); //Cond
}
m_loading_mutex.unlock();
// When all loaded, bring them online
bring_loaded_online();
return;
}
}
編集: Windows クリティカル セクション ラッパー - Mutex.h & Mutex.cpp
#pragma once
#include <windows.h>
#include "Types.h"
#include "OS.h"
class Mutex
{
public:
Mutex();
~Mutex();
void lock();
void unlock();
CRITICAL_SECTION handle();
private:
CRITICAL_SECTION m_cs;
friend class Cond;
};
#include "Mutex.h"
namespace crown
{
namespace os
{
//-----------------------------------------------------------------------------
Mutex::Mutex()
{
InitializeCriticalSection(&m_cs);
}
//-----------------------------------------------------------------------------
Mutex::~Mutex()
{
DeleteCriticalSection(&m_cs);
}
//-----------------------------------------------------------------------------
void Mutex::lock()
{
TryEnterCriticalSection(&m_cs);
}
//-----------------------------------------------------------------------------
void Mutex::unlock()
{
LeaveCriticalSection(&m_cs);
}
//-----------------------------------------------------------------------------
CRITICAL_SECTION Mutex::handle()
{
return m_cs;
}
理由を説明していただけますか?ソリューション?ありがとう!