1

在我们的项目中,我们需要为每个操作系统(linux、android、osx 和 win)实现依赖于操作系统的抽象(如文件、套接字、线程......)。实现 os 抽象的一般迭代是:

  1. 编写一个独立于操作系统的类头,它定义了每个操作系统通用的方法(Cond)。
  2. 使用 os 函数(例如 pthread_cond、win32 ConditionVariable)编写一个 os依赖的实现。
  3. 通过 cmake 链接和构建。

我在 Windows 中实现条件变量时遇到了问题。我需要在我的 Mutex 类中包装 CriticalSection 函数,因为 Windows 中的 ConditionVariable 可用于关键部分。当然,我在 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) 实施 (win) - 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

为什么?不知道。解决方案:使用包装平台依赖项的可移植且免费可用的库。

  • std::thread对于多线程:#include <thread>
  • Boost.Asio用于网络:#include <boost/asio.hpp>
  • Boost.FileSystem用于文件系统:#include <boost/filesystem.hpp>

Boost 库通常是标准库的先驱。Boost.Thread中几乎所有的线程特性都比最新的 C++11 标准早了几年。预计 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 的副本,这是您无法做到的。而是返回引用或指针。

如评论中所述,您还应该在 Mutex 和 Cond 类中实现私有复制构造函数和赋值运算符,因为无法复制依赖于平台的互斥体(例如 pthread_mutex_t)和条件变量 - 这样做会导致使用这些对象时出现未定义的行为

于 2013-06-13T13:23:41.013 回答