我有一个控制台应用程序,在超时信号之后,应该逐个元素地解析2D矩阵(15 * 1200)并将其插入到数据库中。由于操作非常耗时,因此我使用QConcurrent::run
在新线程中执行插入操作。
但是,由于超时信号,一个线程可能在一个完成之前启动,因此可能会发生对数据库的多次访问。 作为解决方案,我试图在特定的 线程中缓冲所有数据库操作,换句话说,将特定线程分配给数据库类,但不知道如何这样做。
答案 0 :(得分:2)
您的问题是经典的并发数据分析问题。您是否尝试过使用std::mutex
?以下是您如何使用它:
您创建了一个可由所有相关线程访问的变量std::mutex
(互斥=互斥)。
std::mutex myLock;
然后,让我们说处理数据的函数如下所示:
void processData(const Data& myData)
{
ProcessedData d = parseData();
insertToDatabase(d);
}
根据我的理解,您担心多个线程会同时调用insertToDatabase(d)
。现在要解决这个问题,只需执行以下操作:
void processData(const Data& myData)
{
ProcessedData d = parseData();
myLock.lock();
insertToDatabase(d);
myLock.unlock();
}
现在有了这个,如果另一个线程试图访问同一个函数,它将阻塞,直到另一个所有其他线程完成。因此线程相互排除一起访问该呼叫。
有关此内容的更多信息:
注意事项:
此互斥锁对象必须与所有线程看到的相同,否则这是无用的。所以要么把它全局化(糟糕的想法,但会起作用),要么将它放在将要进行调用的类中。
互斥对象是不可复制的。因此,如果将它们包含在类中,则应该将互斥对象作为指针,或者应该重新实现该类的复制构造函数以防止复制该互斥锁,或者使用delete
使您的类不可复制:
class MyClass
{
//... stuff
MyClass(const MyClass& src) = delete;
//... other stuff
};
使用std::mutex
的方式更为方便,包括std::lock_guard
和std::unique_lock
,它们拥有互斥锁并为您执行锁定。如果您知道调用insertToDatabase(d);
可能会抛出异常,那么这很好用。在这种情况下,仅使用我编写的代码将无法解锁互斥锁,程序将达到死锁。
在我提供的示例中,您可以使用lock_guard
:
void processData(const Data& myData)
{
ProcessedData d = parseData();
std::lock_guard<std::mutex> guard(myLock);
insertToDatabase(d);
//it will unlock automatically at the end of this function, when the object "guard" is destroyed
}