Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/160.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/multithreading/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 在多线程c++;_C++_Multithreading_Critical Section - Fatal编程技术网

C++ 在多线程c++;

C++ 在多线程c++;,c++,multithreading,critical-section,C++,Multithreading,Critical Section,我构建了一个小应用程序,它有一个渲染线程和一些工作线程,用于可以在渲染附近执行的任务,例如将文件上载到某个服务器上。现在,在这些工作线程中,我使用不同的对象来存储反馈信息,并与渲染线程共享这些信息,以读取它们以用于输出目的。所以render=输出,worker=输入。这些共享对象是int、float、bool、STL string和STL list 我让它运行了几个月,除了在输出期间发生2次随机崩溃外,一切都很好,但我现在了解了线程同步。我读取int、bool等不需要同步,我认为这是有意义的,但

我构建了一个小应用程序,它有一个渲染线程和一些工作线程,用于可以在渲染附近执行的任务,例如将文件上载到某个服务器上。现在,在这些工作线程中,我使用不同的对象来存储反馈信息,并与渲染线程共享这些信息,以读取它们以用于输出目的。所以render=输出,worker=输入。这些共享对象是int、float、bool、STL string和STL list

我让它运行了几个月,除了在输出期间发生2次随机崩溃外,一切都很好,但我现在了解了线程同步。我读取int、bool等不需要同步,我认为这是有意义的,但当我查看字符串和列表时,我担心如果两个线程同时尝试读取/写入一个对象,可能会崩溃。基本上,我希望一个线程更改字符串的大小,而另一个线程可能使用过时的大小循环遍历其字符,然后从未分配的内存中读取。今天晚上,我想构建一个小测试场景,用两个线程在一个循环中写/读同一个对象,不过我也希望在这里得到一些想法

我在读Win32中的CriticalSection,认为它可能值得一试。然而,我不确定实施它的最佳方式是什么。如果我把它放在一个读/函数的开始和结尾,感觉好像浪费了一些时间。如果我将EnterCriticalSection和LeaveCriticalSection包装在集合中,并为我希望跨线程同步的每个对象获取函数,那么就需要进行大量的管理

我想我必须浏览更多的参考资料


好吧,我还是不知道该怎么做。我正在研究StackedCrooked提供的链接,但仍然没有如何做到这一点的图像

我现在将复制/修改的内容放在一起,不知道如何继续或做什么:有人有想法吗

class CSync
{
public:
    CSync()
    : m_isEnter(false)
    { InitializeCriticalSection(&m_CriticalSection); }
    ~CSync()
    { DeleteCriticalSection(&m_CriticalSection); }
    bool TryEnter()
    {
        m_isEnter = TryEnterCriticalSection(&m_CriticalSection)==0 ? false:true;
        return m_isEnter;
    }
    void Enter()
    {
        if(!m_isEnter)
        {
            EnterCriticalSection(&m_CriticalSection);
            m_isEnter=true;
        }
    }
    void Leave()
    {
        if(m_isEnter)
        {
            LeaveCriticalSection(&m_CriticalSection);
            m_isEnter=false;
        }
    }

private:
    CRITICAL_SECTION m_CriticalSection;
    bool m_isEnter;
};

/* not needed

class CLockGuard
{
public:
    CLockGuard(CSync& refSync) : m_refSync(refSync) { Lock(); }
    ~CLockGuard() { Unlock(); }

private:
    CSync& m_refSync;

    CLockGuard(const CLockGuard &refcSource);
    CLockGuard& operator=(const CLockGuard& refcSource);
    void Lock() { m_refSync.Enter(); }
    void Unlock() { m_refSync.Leave(); }
};*/

template<class T> class Wrap
{
public:
    Wrap(T* pp, const CSync& sync)
        : p(pp)
        , m_refSync(refSync)
    {}
    Call_proxy<T> operator->() { m_refSync.Enter(); return Call_proxy<T>(p); }
private:
    T* p;
    CSync& m_refSync;
};

template<class T> class Call_proxy
{
public:
    Call_proxy(T* pp, const CSync& sync)
        : p(pp)
        , m_refSync(refSync)
    {}
    ~Call_proxy() { m_refSync.Leave(); }
    T* operator->() { return p; }
private:
    T* p;
    CSync& m_refSync;
};


int main
{
    CSync sync;
    Wrap<string> safeVar(new string);
    // safeVar what now?
    return 0;
};

刚刚添加了更多内容,现在调用clear()时崩溃。好


规则很简单:如果对象可以在任何线程中修改,那么对它的所有访问都需要同步。对象的类型无关紧要:即使是
bool
int
也需要某种类型的外部同步(可能通过特殊的、依赖于系统的函数,而不是使用锁)。没有例外,至少在C++中是这样。(如果您愿意使用内联汇编程序,并且理解围栏和内存障碍的含义,您可能能够避免锁定。)

规则很简单:如果可以在任何线程中修改对象,则对它的所有访问都需要同步。对象的类型无关紧要:即使是
bool
int
也需要某种类型的外部同步(可能通过特殊的、依赖于系统的函数,而不是使用锁)。没有例外,至少在C++中是这样。(如果您愿意使用内联汇编程序,并且了解围栏和内存屏障的含义,您可能能够避免锁定。)

首先,即使访问最原始的数据类型,您也需要保护。 如果你在某处有一个
intx
,你可以写

x += 42;
。。。但这意味着,在最低级别:读取x的旧值,计算新值,将新值写入变量x。如果两个线程同时执行此操作,则会发生奇怪的事情。您需要一个锁定/关键部分

我建议使用C++11和相关接口,或者,如果没有,使用boost::thread库中相应的东西。如果这也不是一个选项,请参阅Win32和Unix的pthread_mutex_*上的关键部分

不,不要开始编写多线程程序! 让我们先谈谈不变量。 在(假设的)定义良好的程序中,每个类都有一个不变量。 不变量是关于实例状态(即关于其所有成员变量的值)始终为真的逻辑语句。如果不变量变为false,则对象已损坏,程序可能会崩溃,坏事情已经发生。所有函数在被调用时都假定不变量为真,并且它们确保在调用后不变量仍然为真

当成员函数更改成员变量时,不变量可能会暂时变为false,但这是可以的,因为成员函数将确保在退出之前所有内容都再次“匹配”


您需要一个保护不变式的锁—每当您执行可能影响不变式的操作时,请获取锁并在确保恢复不变式之前不要释放它。

首先,您确实需要保护,即使是访问最基本的数据类型。 如果你在某处有一个
intx
,你可以写

x += 42;
。。。但这意味着,在最低级别:读取x的旧值,计算新值,将新值写入变量x。如果两个线程同时执行此操作,则会发生奇怪的事情。您需要一个锁定/关键部分

我建议使用C++11和相关接口,或者,如果没有,使用boost::thread库中相应的东西。如果这也不是一个选项,请参阅Win32和Unix的pthread_mutex_*上的关键部分

不,不要开始编写多线程程序! 让我们先谈谈不变量。 在(假设的)定义良好的程序中,每个类都有一个不变量。 不变量是关于实例状态(即关于其所有成员变量的值)始终为真的逻辑语句。如果不变量变为false,则对象已损坏,程序可能会崩溃,坏事情已经发生。所有函数在被调用时都假定不变量为真,并且它们确保在调用后不变量仍然为真

当成员函数更改成员变量时,不变量可能会暂时变为false,但这是可以的,因为成员函数将确保所有内容都“匹配”
x += 42;