logo
down
shadow

Could this publish / check-for-update class for a single writer + reader use memory_order_relaxed or acquire/release for


Could this publish / check-for-update class for a single writer + reader use memory_order_relaxed or acquire/release for

Content Index :

Could this publish / check-for-update class for a single writer + reader use memory_order_relaxed or acquire/release for
Tag : cpp , By : Thomas Plunkett
Date : January 12 2021, 01:40 AM

To fix this issue Your writer only needs release, not seq-cst, but relaxed is too weak. You can't publish a value for m_position until after the non-atomic assignment to the corresponding m_buffer[] entry. You need release ordering to make sure the m_position store is visible to other threads only after all earlier memory operations. (Including the non-atomic assignment). https://preshing.com/20120913/acquire-and-release-semantics/
This has to "synchronize-with" an acquire or seq_cst load in the reader. Or at least mo_consume in the reader.
    // Possible failure mode: writer wraps around between reads, leaving same m_position
    // single-reader
    const bool read(T &elem)
    {
        // FIXME: big hack to get this in a separate cache line from the instance vars
        // maybe instead use alignas(64) int m_lastread as a class member, and/or on the other side of m_buffer from m_position.
        static int lastread = -1;

        int wPos = m_position.load(std::memory_order_acquire);    // or cheat with relaxed to get asm that's like "consume"
        if (lastread == wPos)
            return false;

        elem = m_buffer[wPos];
        lastread = wPos;
        return true;
    }

template<typename T>
class WaitFreePublish
{

private:
    struct {
        alignas(32) T elem;           // at most 2 elements per cache line
        std::atomic<int8_t> claimed;  // writers sets this to 0, readers try to CAS it to 1
                                      // could be bool if we don't end up needing 3 states for anything.
                                      // set to "1" in the constructor?  or invert and call it "unclaimed"
    } m_buffer[maxElements];

    std::atomic<int> m_position {-1};
}
/// claimed flag per array element supports concurrent readers

    // thread-safety: single-writer only
    // update claimed flag first, then element, then m_position.
    void publish(const T& elem)
    {
        const int wPos = m_position.load(std::memory_order_relaxed);
        const int nextPos = getNextPos(wPos);

        m_buffer[nextPos].claimed.store(0, std::memory_order_relaxed);
        std::atomic_thread_fence(std::memory_order_release);  // make sure that `0` is visible *before* the non-atomic element modification
        m_buffer[nextPos].elem = elem;

        m_position.store(nextPos, std::memory_order_release);
    }

    // thread-safety: multiple readers are ok.  First one to claim an entry gets it
    // check claimed flag before/after to detect overwrite, like a SeqLock
    const bool read(T &elem)
    {
        int rPos = m_position.load(std::memory_order_acquire);

        int8_t claimed = m_buffer[rPos].claimed.load(std::memory_order_relaxed);
        if (claimed != 0)
            return false;      // read-only early-out

        claimed = 0;
        if (!m_buffer[rPos].claimed.compare_exchange_strong(
                claimed, 1, std::memory_order_acquire, std::memory_order_relaxed))
            return false;  // strong CAS failed: another thread claimed it

        elem = m_buffer[rPos].elem;

        // final check that the writer didn't step on this buffer during read, like a SeqLock
        std::atomic_thread_fence(std::memory_order_acquire);    // LoadLoad barrier

        // We expect it to still be claimed=1 like we set with CAS
        // Otherwise we raced with a writer and elem may be torn.
        //  optionally retry once or twice in this case because we know there's a new value waiting to be read.
        return m_buffer[rPos].claimed.load(std::memory_order_relaxed) == 1;

        // Note that elem can be updated even if we return false, if there was tearing.  Use a temporary if that's not ok.
    }

Comments
No Comments Right Now !

Boards Message :
You Must Login Or Sign Up to Add Your Comments .

Share : facebook icon twitter icon

Single Responsibility Principle: Should I separate my bibliography class in Reader, Writer and Container class?


Tag : development , By : Frank Rotolo
Date : March 29 2020, 07:55 AM
I hope this helps you . I like the approach of separating "container" classes from reader/writer/getter and so on, preferably defined by an interface. Search for "strategy pattern" and you will find more information about it.
A simple approach would be to have the Bibliography class accept an IBibliographyReader in its constructor, and then have a class implement that interface. When creating a Bibliography class you pass an instance of the concrete reader implementation to it.

Thread safety of multiple-reader/single-writer class


Tag : cpp , By : Caleb Ames
Date : March 29 2020, 07:55 AM
I hope this helps . This is an interesting use of shared_ptr to implement thread safety. Whether it is OK depends on the thread-safety guarantees of boost::shared_ptr. In particular, does it establish some sort of fence or membar, so that you are guaranteed that all of the writes in the constructor and insert functions of set occur before any modification of the pointer value becomes visible.
I can find no thread safety guarantees whatsoever in the Boost documentation of smart pointers. This surprizes me, as I was sure that there was some. But a quick look at the sources for 1.47.0 show none, and that any use of boost::shared_ptr in a threaded environment will fail. (Could someone please point me to what I'm missing. I can't believe that boost::shared_ptr has ignored threading.)

Multiple-Reader, Single-Writer Lock in Boost WITH Writer Block


Tag : cpp , By : ArdentRogue
Date : March 29 2020, 07:55 AM
To fix the issue you can do The answer here almost does what I want. , Found it. I needed unique_lock instead of upgrade_to_unique_lock:
boost::shared_mutex _access;
void reader()
{
    // get shared access
    boost::shared_lock<boost::shared_mutex> lock(_access);
}

void writer()
{
    // wait for old shared access readers to finish
    // but block out new shared access readers
    boost::unique_lock<boost::shared_mutex> uniqueLock(_access);
}

How can I implement a C++ Reader-Writer lock using a single unlock method, which can be called be a reader or writer?


Tag : cpp , By : user107021
Date : March 29 2020, 07:55 AM
wish of those help Well, define two functions UnlockRead and UnlockWrite.
I believe you do not need both accesses (Write/Read) at the same time in the same place. So what I am proposing is to have two other classes for locking access:
class ReadWriteAccess
{
public:
   ReadWriteAccess(uint32_t maxReaders);
   ~ReadWriteAccess();
   uint32_t GetMaxReaders() const;
   uint32_t GetMaxReaders() const;
   eResult  GetReadLock(int32_t timeout);
   eResult  GetWriteLock(int32_t timeout);
   eResult  UnlockWrite();
   eResult  UnlockRead();

private:
   uint32_t m_MaxReaders;
   Mutex* m_WriterMutex;
   Semaphore* m_ReaderSemaphore;

};
class ReadLock
{
public:
    ReadLock(ReadWriteAccess& access, int32_t timeout) : access(access) 
    {
        result = access.GetReadLock(timeout);
    }
    eResult getResult() const { return result; }
    ~ReadLock()
    {
        if (result)
            access.UnlockRead();
    }
private:
    ReadWriteAccess& access;
    eResult  result;
};
T someResource;
ReadWriteAccess someResourceGuard;

void someFunction()
{
    ReadLock lock(someResourceGuard);
    if (lock.getResult())
       cout << someResource; // it is safe to read something from resource
}
class ReadWriteLock
{
public:
   ReadWriteLock(uint32_t maxReaders);
   ~ReadWriteLock();
   uint32_t GetMaxReaders() const;
   eResult  GetReadLock(int32_t timeout)
   {
       eResult result = GetReadLockImpl(timestamp);
       if (result)
           lockStack.push(READ);
   }
   eResult  GetWriteLock(int32_t timeout)
   {
       eResult result = GetWriteLockImpl(timestamp);
       if (result)
           lockStack.push(WRITE);
   }
   eResult  Unlock()
   {
       LastLockMode lockMode = lockStack.top();
       lockStack.pop();
       if (lockMode == READ) 
           UnlockReadImpl();
       else
           UnlockWriteImpl();
   }

private:
   uint32_t m_MaxReaders;
   Mutex* m_WriterMutex;
   Semaphore* m_ReaderSemaphore;

    enum Mode { READ, WRITE };
    std::stack<Mode> lockStack;
};
template <typename Value>
class MultiThreadStack
{
public:
    void push(Value)
    {
       stackPerThread[getThreadId()].push(value);
    }
    Value top()
    {
       return stackPerThread[getThreadId()].top();
    }
    void pop()
    {
       stackPerThread[getThreadId()].pop();
    }
private:
    ThreadId getThreadId() { return /* your system way to get thread id*/; }
    std::map<ThreadId, std::stack<Value>> stackPerThread;
};

ReentrantReadWriteLock - why can't reader acquire writer's lock?


Tag : java , By : Hadley
Date : March 29 2020, 07:55 AM
Related Posts Related QUESTIONS :
  • Reference to end is ambiguous
  • Problem with basic usage of std::enable_if
  • How to print out a decimal number as octal number using setiosflags in C++
  • Open Visual Studio with solution and specific file and line
  • Enum value based on template type
  • Is there any way to swap nodes in std::list?
  • How to copy QString into wchar_t buffer
  • Make the compiler generate an empty default function for an std::function
  • Insert or push_back to end of a std::vector?
  • Best practice for const temporary types
  • Include CSV File in Complied Binary
  • Issue with binding non static function to callback
  • How can read from some files and write content of them with different form into files with same names
  • Why does auto deduce this variable as double and not float?
  • no instance of overloaded function "std::make_unique" matches the argument list, but works with unique_ptr con
  • How to see array size from a pointer in c++
  • Error taking address of temporary in Eclipse
  • Using an iterator to go through a vector and modify the contents
  • Are extern extern "C", and extern "C" extern, allowed?
  • Can't solve C2660 and C2065 Errors
  • C referencing C++ extern
  • How to write the definition of a derived class in c++?
  • Why when I include <cmath> I need to use the namespace std too?
  • How to assign a 32-bit unsigned integer to a bit field containing 32 bits
  • Why does the same class being defined in multiple .cpp files not cause a linker multiple definition error?
  • C++ 11db error when trying to quit the program in xcode. beginner level
  • Add content of a vector into a Capnproto map object
  • Recursively Pass Template Template To a Template Template Function
  • Swap rows in a 2D array with std::swap. How does it work?
  • Is there any situation in which an object's storage might change during its lifetime?
  • clang++ always generates empty profraw coverage reports
  • Do memory leaks persist after program completion if the OS does not clear it?
  • How to link library using cmake
  • How to use getters and setters without generating a copy?
  • Generating multiple amounts of the same sprite broken
  • function in c++ why my compiler didn't recognize the error()
  • Relationship between copy(...) and copy(seq, ...)
  • Are <cmath> functions required to be `noexcept` in C++17?
  • How to find a struct list item
  • How can you handle DLL versions when referencing C++ DLL's over COM from VBScript with CreateObject?
  • Do not understand how c++ set works
  • Actual build date in C++
  • How to link to already compiled external shared libraries in RCPP using Makevars?
  • combination of enable_if + std::less + sizeof... makes MSVC fail
  • Can you call the destructor without calling the constructor?
  • How do I prevent a function from freeing memory of a local variable?
  • Why am I getting an exception with a push involved with a shared pointer?
  • Resizing an array by pointer
  • avoiding dynamic_cast without increasing coupling
  • I cannot solve the else part in my if-else ladder?
  • Inherit from arbitrary class in c++?
  • LNK2019 unresolved external symbol from MSVCRTD.lib
  • Do I need to free wchar memory allocated when using 'new' or does delete[] also free it?
  • Object creation with varying buffer size
  • Is there a way to save a variable in an std::string?
  • template lambda vs functor with template operator()
  • How to release boost::interprocess::named_mutex when the process crashes
  • How do I implement the Interface Segregation Principle using smart pointers in C++?
  • Why is my getline not reading .csv files properly?
  • size of 2d array passed into a function
  • shadow
    Privacy Policy - Terms - Contact Us © scrbit.com