对我来说,在这里使用互斥锁似乎更方便。一般来说,共享引用时不使用互斥锁可能会导致问题。在这里使用互斥锁的唯一缺点似乎是,您会稍微降低性能,因为您的线程必须相互等待。
会发生什么样的错误?
就像评论中的某个人所说,如果您共享基本数据类型,例如 int、bool、float 或对象引用,情况会有所不同。我添加了一些 qt 代码示例,其中强调了在不使用互斥锁期间可能出现的 2 个问题。问题 #3 是一个基本问题,Benjamin T 和他的好答案详细描述了这个问题。
块引用
主文件
#include <QCoreApplication>
#include <QThread>
#include <QtDebug>
#include <QTimer>
#include "countingthread.h"
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
int amountThread = 3;
int counter = 0;
QString *s = new QString("foo");
QMutex *mutex = new QMutex();
//we construct a lot of thread
QList<CountingThread*> threadList;
//we create all threads
for(int i=0;i<amountThread;i++)
{
CountingThread *t = new CountingThread();
#ifdef TEST_ATOMIC_VAR_SHARE
t->addCounterdRef(&counter);
#endif
#ifdef TEST_OBJECT_VAR_SHARE
t->addStringRef(s);
//we add a mutex, which is shared to read read write
//just used with TEST_OBJECT_SHARE_FIX define uncommented
t->addMutexRef(mutex);
#endif
//t->moveToThread(t);
threadList.append(t);
}
//we start all with low prio, otherwise we produce something like a fork bomb
for(int i=0;i<amountThread;i++)
threadList.at(i)->start(QThread::Priority::LowPriority);
return a.exec();
}
计数线程.h
#ifndef COUNTINGTHREAD_H
#define COUNTINGTHREAD_H
#include <QThread>
#include <QtDebug>
#include <QTimer>
#include <QMutex>
//atomic var is shared
//#define TEST_ATOMIC_VAR_SHARE
//more complex object var is shared
#define TEST_OBJECT_VAR_SHARE
// we add the fix
#define TEST_OBJECT_SHARE_FIX
class CountingThread : public QThread
{
Q_OBJECT
int *m_counter;
QString *m_string;
QMutex *m_locker;
public :
void addCounterdRef(int *r);
void addStringRef(QString *s);
void addMutexRef(QMutex *m);
void run() override;
};
#endif // COUNTINGTHREAD_H
计数线程.cpp
#include "countingthread.h"
void CountingThread::run()
{
//forever
while(1)
{
#ifdef TEST_ATOMIC_VAR_SHARE
//first use of counter
int counterUse1Copy= (*m_counter);
//some other operations, here sleep 10 ms
this->msleep(10);
//we will retry to use a second time
int counterUse2Copy= (*m_counter);
if(counterUse1Copy != counterUse2Copy)
qDebug()<<this->thread()->currentThreadId()<<" problem #1 found, counter not like we expect";
//we increment afterwards our counter
(*m_counter) +=1; //this works for fundamental types, like float, int, ...
#endif
#ifdef TEST_OBJECT_VAR_SHARE
#ifdef TEST_OBJECT_SHARE_FIX
m_locker->lock();
#endif
m_string->replace("#","-");
//this will crash here !!, with problem #2,
//segmentation fault, is not handle by try catch
m_string->append("foomaster");
m_string->append("#");
if(m_string->length()>10000)
qDebug()<<this->thread()->currentThreadId()<<" string is: " << m_string;
#ifdef TEST_OBJECT_SHARE_FIX
m_locker->unlock();
#endif
#endif
}//end forever
}
void CountingThread::addCounterdRef(int *r)
{
m_counter = r;
qDebug()<<this->thread()->currentThreadId()<<" add counter with value: " << *m_counter << " and address : "<< m_counter ;
}
void CountingThread::addStringRef(QString *s)
{
m_string = s;
qDebug()<<this->thread()->currentThreadId()<<" add string with value: " << *m_string << " and address : "<< m_string ;
}
void CountingThread::addMutexRef(QMutex *m)
{
m_locker = m;
}
如果您跟进代码,您可以执行 2 次测试。
如果您在countingthread.h 中取消注释TEST_ATOMIC_VAR_SHARE 并注释TEST_OBJECT_VAR_SHARE,您将看到
问题 #1如果您在线程中多次使用变量,则可能是来自另一个线程的后台更改,除了我的预期之外,在使用 int 计数器执行期间,我的构建环境中没有应用程序崩溃或奇怪的异常。
如果您在countingthread.h 中取消注释TEST_OBJECT_VAR_SHARE并注释TEST_OBJECT_SHARE_FIX 和注释TEST_ATOMIC_VAR_SHARE,您将看到
问题 #2你得到一个分段错误,这是无法通过 try catch 处理的。这是因为多个线程正在使用字符串函数对同一对象进行编辑。
如果您也取消注释TEST_OBJECT_SHARE_FIX,您会看到通过互斥锁进行的正确处理。
问题 #3见Benjamin T 的回答
什么是互斥锁:
我真的很喜欢vallabh 建议的鸡肉解释。
我也在这里找到了一个很好的解释