C++ 在多线程c++;
我构建了一个小应用程序,它有一个渲染线程和一些工作线程,用于可以在渲染附近执行的任务,例如将文件上载到某个服务器上。现在,在这些工作线程中,我使用不同的对象来存储反馈信息,并与渲染线程共享这些信息,以读取它们以用于输出目的。所以render=输出,worker=输入。这些共享对象是int、float、bool、STL string和STL list 我让它运行了几个月,除了在输出期间发生2次随机崩溃外,一切都很好,但我现在了解了线程同步。我读取int、bool等不需要同步,我认为这是有意义的,但当我查看字符串和列表时,我担心如果两个线程同时尝试读取/写入一个对象,可能会崩溃。基本上,我希望一个线程更改字符串的大小,而另一个线程可能使用过时的大小循环遍历其字符,然后从未分配的内存中读取。今天晚上,我想构建一个小测试场景,用两个线程在一个循环中写/读同一个对象,不过我也希望在这里得到一些想法 我在读Win32中的CriticalSection,认为它可能值得一试。然而,我不确定实施它的最佳方式是什么。如果我把它放在一个读/函数的开始和结尾,感觉好像浪费了一些时间。如果我将EnterCriticalSection和LeaveCriticalSection包装在集合中,并为我希望跨线程同步的每个对象获取函数,那么就需要进行大量的管理 我想我必须浏览更多的参考资料C++ 在多线程c++;,c++,multithreading,critical-section,C++,Multithreading,Critical Section,我构建了一个小应用程序,它有一个渲染线程和一些工作线程,用于可以在渲染附近执行的任务,例如将文件上载到某个服务器上。现在,在这些工作线程中,我使用不同的对象来存储反馈信息,并与渲染线程共享这些信息,以读取它们以用于输出目的。所以render=输出,worker=输入。这些共享对象是int、float、bool、STL string和STL list 我让它运行了几个月,除了在输出期间发生2次随机崩溃外,一切都很好,但我现在了解了线程同步。我读取int、bool等不需要同步,我认为这是有意义的,但
好吧,我还是不知道该怎么做。我正在研究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;