OpenMP中的多个读者,单个写入器锁

时间:2017-07-25 03:31:17

标签: multithreading openmp mutex atomic readerwriterlock

有多个线程共享一个对象来读取和写入,我需要使用具有以下功能的读写器锁来实现该类:

  • 它可能被一个且不超过一个线程声明占用。尝试占用它的任何其他线程将拒绝继续以完成其工作而不是被阻止
  • 任何线程都可以随时询问该对象是被自己还是被其他人占用,除非它被宣布占用或释放。
  • 只允许该对象的所有者释放其所有权,但其他人也可能尝试这样做。如果不是所有者,则取消释放操作。
  • 需要仔细考虑性能。

我正在使用OpenMP进行工作,因此我希望仅使用OpenMP中的API而不是POSIX等来实现锁定。我已阅读this answer,但只有C ++标准库实现的解决方案。由于将OpenMP与C ++标准库或POSIX线程模型混合可能会降低程序速度,我想知道OpenMP有一个很好的解决方案吗?

我试过这样的事情,有时它工作得很好,但有时它会崩溃,有时会被锁死。我发现很难调试。

virtualenv

原子变量,互斥锁和互斥锁使用OpenMP指令实现,如下所示:

class Element
{
  public:
    typedef int8_t label_t;
    Element() : occupied_(-1) {}

    // Set it occupied by thread @myThread.
    // Return whether it is set successfully.
    bool setOccupiedBy(const int myThread)
    {
        if (lock_.try_lock())
        {
            if (occupied_ == -1)
            {
                occupied_ = myThread;
                ready_.set(true);
            }
        }
        // assert(lock_.get() && ready_.get());
        return occupied_ == myThread;
    }

    // Return whether it is occupied by other threads
    // except for thread @myThread.
    bool isOccupiedByOthers(const int myThread) const
    {
        bool value = true;
        while (lock_.get() != ready_.get());
        value = occupied_ != -1 && occupied_ != myThread;
        return value;
    }

    // Return whether it is occupied by thread @myThread.
    bool isOccupiedBySelf(const int myThread) const
    {
        bool value = true;
        while (lock_.get() != ready_.get());
        value = occupied_ == myThread;
        return value;
    }

    // Clear its occupying mark by thread @myThread.
    void clearOccupied(const int myThread)
    {
        while (true)
        {
            bool ready = ready_.get();
            bool lock = lock_.get();
            if (!ready && !lock)
                return;
            if (ready && lock)
                break;
        }
        label_t occupied = occupied_;
        if (occupied == myThread)
        {
            ready_.set(false);
            occupied_ = -1;
            lock_.unlock();
        }
        // assert(ready_.get() == lock_.get());
    }

 protected:
    Atomic<label_t> occupied_;

    // Locked means it is occupied by one of the threads,
    // and one of the threads might be modifying the ownership
    MutexLock lock_;

    // Ready means it is occupied by one the the threads,
    // and none of the threads is modifying the ownership.
    Mutex ready_;
};

我也使用OpenMP提供的锁定替代:

template <typename T>
class Atomic
{
  public:
    Atomic() {}
    Atomic(T&& value) : mutex_(value) {}

    T set(const T& value)
    {
        T oldValue;
#pragma omp atomic capture
        {
            oldValue = mutex_;
            mutex_ = value;
        }
        return oldValue;
    }
    T get() const
    {
        T value;
#pragma omp read
        value = mutex_;
        return value;
    }
    operator T() const { return get(); }
    Atomic& operator=(const T& value)
    {
        set(value);
        return *this;
    }
    bool operator==(const T& value) { return get() == value; }
    bool operator!=(const T& value) { return get() != value; }

  protected:
    volatile T mutex_;
};

class Mutex : public Atomic<bool>
{
  public:
    Mutex() : Atomic<bool>(false) {}
};

class MutexLock : private Mutex
{
  public:
    void lock()
    {
        bool oldMutex = false;
        while (oldMutex = set(true), oldMutex == true) {}
    }
    void unlock() { set(false); }
    bool try_lock()
    {
        bool oldMutex = set(true);
        return oldMutex == false;
    }
    using Mutex::operator bool;
    using Mutex::get;
};

顺便说一句,我在x86_64 GNU / Linux上使用gcc 4.9.4和OpenMP 4.0。

0 个答案:

没有答案