代码之家  ›  专栏  ›  技术社区  ›  Coder

C++中的易失类

  •  0
  • Coder  · 技术社区  · 14 年前

    我有一个关于volatile关键字的问题,我似乎找不到答案。

    在我的应用程序中,我有一个作为线程之间的状态缓冲区共享的数据类,我需要它从多个线程定期更新。

    类如下所示:

    class CBuffer
    {
        //Constructor, destructor, Critical section initialization/destruction
        //...
    
        volatile wstring m_strParam;
        //...
        void InterlockedParamSetter(const wstring &strIn);
        wstring InterlockedParamGetter();
    
        ParamSetter(const wstring &strIn);
        wstring ParamGetter();
    
        Lock();
        Unlock();
    }
    
    void CBuffer::InterlockedParamSetter(const wstring &strIn)
    {
        Lock();
        const_cast<wstring>(m_strParam) = strIn;
        Unlock();
    }
    
    //... other f-ns
    

    但是编译器抱怨const\u cast转换。

    这看起来像是我在滥用volatile关键字,但同时,我不能让params在调用之间被缓存,因为如果两个或三个线程分配它们,可能会出错。

    如何在C++中编写线程/缓存安全类?

    注意:到目前为止,锁定还不是瓶颈,而且锁几乎都是单行的,所以从性能的角度来看,序列化和锁定目前还不是问题。当然,如果有更好的算法,我很乐意听。

    编辑: 我还不清楚。。。

    考虑这个例子(内联+链接时间codegen);

    void Thread1Func()
    {
        //Unrolled, inlined InterlockedParamSetter()
        EnterCriticalSection(&cs);
        WriteTo(CBuffer::m_strParam);//write to buffer, wstring not volatile, cache it
        LeavCriticalSection(&cs);
        //Unroll end
    
        //DoSomethingElse
    
        //!!!!Thread 2 does InterlockedParamSetter
        //which causes wstring::reserve and invalidates old pointers!!!!
    
        //Unrolled, inlined InterlockedParamSetter()
        EnterCriticalSection(&cs);
        WriteTo(CBuffer::m_strParam);//oh, good, we have a pointer to old buffer
        //cached in one of the registers, write to it -> access violation
        LeavCriticalSection(&cs);
        //Unroll end
    }
    
    4 回复  |  直到 14 年前
        1
  •  2
  •   Anthony Williams    14 年前

    在可移植代码中, volatile 绝对与多线程无关 .

    作为扩展 不稳定的 -限定的简单本机类型,如 int 可以用于原子访问的简单读取和存储操作,但是 扩展到读修改写访问,例如 i++ 或类类型的对象,例如 std::string

    m_strParam 来自多个线程的变量,每个线程必须在访问之前锁定关联的互斥锁 ,然后解锁。锁定/解锁将确保 穆斯塔帕拉姆 如果另一个线程通过下一个锁修改了变量,则不会缓存内部指针。

    如果正确使用锁,则不需要 限定符,也不需要使用 const_cast .

        2
  •  2
  •   Vijay Mathew Chor-ming Lung    14 年前

    const_cast 请不要用标准参数:

    m_strParam = const_cast<wstring> (strIn);
    

    volatile 不保证原子性,在编写可移植、线程安全的程序时毫无用处。请参见以下链接:

        3
  •  2
  •   ereOn    14 年前

    std::string (和 std::wstring

    确保线程安全的通常方法是在需要的地方使用互斥量、信号量,并避免使用全局变量。

        4
  •  0
  •   rwong    14 年前

    不需要使用 volatile . A compiler memory barrier 应该足够了。这个 Lock / Unlock

    class CBuffer
    {
        //Constructor, destructor, Critical section initialization/destruction ...
        wstring m_strParam;
    };
    
    void CBuffer::InterlockedParamSetter(const wstring &strIn)    
    {
        Lock();
        //compiler-specific memory barrier;
        m_strParam = strIn;
        //compiler-specific memory barrier;
        Unlock();
    }
    

    虽然在某些编译器上 不稳定的 关键字在应用于诸如 wstring . 例如: VC++

    类似于用 易失性(C++)关键字。然而,一个 记忆屏障更有效 因为。。。