1

私たちのプロジェクトでは、OS (Linux、Android、OSX、WIN) ごとにOS依存の抽象化 (ファイル、ソケット、スレッドなど) を実装する必要があります。OS の抽象化を実装するための一般的な iter は次のとおりです。

  1. 各OSに共通のメソッドを定義するOS非依存のクラスヘッダを書く(Cond)。
  2. os 関数を使用してos依存の実装を記述します (例: pthread_cond、win32 ConditionVariable)。
  3. 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;
}

理由を説明していただけますか?ソリューション?ありがとう!

4

2 に答える 2

2

なんで?わかりません。解決策: プラットフォームの依存関係をラップする移植可能で自由に利用できるライブラリを使用します。

Boost ライブラリは、多くの場合、標準ライブラリの前身です。ほとんどすべてのスレッド機能は、最新の C++11 標準の数年前にBoost.Threadで利用できました。Boost.Asio と Boost.Filesystem も標準化のためのビルディング ブロックになると予想されます。

CMakeで動作させるには、Boostをインストールして次のようなものを使用します

find_package(Boost COMPONENTS thread asio filesystem REQUIRED)
于 2013-06-13T12:47:25.407 に答える
1

これは確かに間違っています:

CRITICAL_SECTION Mutex::handle()
{
    return m_cs;
}

CRITICAL_SECTION のコピーを返していますが、これはできません。代わりに参照またはポインターを返します。

コメントで述べたように、プラットフォームに依存するミューテックス (pthread_mutex_t など) と条件変数はコピーできないため、Mutex と Cond クラスにプライベート コピー コンストラクターと代入演算子も実装する必要があります。これらのオブジェクトを使用すると、未定義の動作が発生します。

于 2013-06-13T13:23:41.013 に答える