QSemaphore 是否足以制作 QQueue 的线程安全类比?
Is QSemaphore enough to make a thread safe analogue of QQueue?
我试图制作一个基本的线程安全 QQueue 类比。这个想法是一个线程将数据放入队列,另一个线程处理它。我找到了一个非常基本的解决方案。
#include <QThread>
#include <QQueue>
#include <QSemaphore>
class AsyncQueue
{
public:
void enqueue(const int x);
int dequeue();
private:
QQueue<int> queue;
QSemaphore semaphore;
};
int AsyncQueue::dequeue()
{
semaphore.acquire();
return queue.dequeue();
}
void AsyncQueue::enqueue(const int x)
{
queue.enqueue(x);
semaphore.release();
return;
}
我是多线程新手。它通过了一些最简单的测试,但我怀疑这是否足够?或者队列是否需要 AtomicPointer,以防线程在另一个正在处理队列的最后一项时尝试将新项目入队?
不是,有机会并发 read/write 访问队列,因为没有临界区保护来自 enqueue()
的队列写访问。它总是可以执行,因为 QSemaphore::release()
永远不会阻塞。因此,dequeue()
和enqueue(int)
有很多机会同时执行,造成严重破坏。
您现在拥有的信号量的作用是向队列的消费者端发送信号,告知队列中存在的值的数量。您将需要第二个 QSemaphore
来实现对底层 QQueue
的独占访问,如下(非常肤浅的测试):
#include <QThread>
#include <QQueue>
#include <QSemaphore>
class AsyncQueue
{
public:
void enqueue(const int x);
int dequeue();
private:
QQueue<int> queue;
QSemaphore itemsInQueue;
QSemaphore exclusiveAccess{1};
};
int AsyncQueue::dequeue()
{
itemsInQueue.acquire();
exclusiveAccess.acquire();
int result{queue.dequeue()};
exclusiveAccess.release();
return result;
}
void AsyncQueue::enqueue(const int x)
{
exclusiveAccess.acquire();
queue.enqueue(x);
exclusiveAccess.release();
itemsInQueue.release();
}
如果您可以使用现代编译器,我更愿意使用 STL 对应物来实现它。 std::thread
, std::mutex
, std::lock_guard
, and std::condition_variable
在这方面值得研究。
我想你可以按照下面的方法试试。
基本上文档说:
QSharedPointer and QWeakPointer are thread-safe and operate atomically
on the pointer value. Different threads can also access the
QSharedPointer or QWeakPointer pointing to the same object at the same
time without need for locking mechanisms.
所以你不需要锁定机制.....
如何:?
using sInt = QSharedPointer<int>;
QQueue<sInt> qInt; //Your queue of shared pointer objects.
qInt.enqueue(QSharedPointer<int>::create(5));
qInt.enqueue(QSharedPointer<int>::create(6));
qInt.enqueue(QSharedPointer<int>::create(7));
qInt.enqueue(QSharedPointer<int>::create(8));
//To retrieve the value use either data() or get() as shown below.
sInt value = qInt.dequeue();
int *val = value.data();
我试图制作一个基本的线程安全 QQueue 类比。这个想法是一个线程将数据放入队列,另一个线程处理它。我找到了一个非常基本的解决方案。
#include <QThread>
#include <QQueue>
#include <QSemaphore>
class AsyncQueue
{
public:
void enqueue(const int x);
int dequeue();
private:
QQueue<int> queue;
QSemaphore semaphore;
};
int AsyncQueue::dequeue()
{
semaphore.acquire();
return queue.dequeue();
}
void AsyncQueue::enqueue(const int x)
{
queue.enqueue(x);
semaphore.release();
return;
}
我是多线程新手。它通过了一些最简单的测试,但我怀疑这是否足够?或者队列是否需要 AtomicPointer,以防线程在另一个正在处理队列的最后一项时尝试将新项目入队?
不是,有机会并发 read/write 访问队列,因为没有临界区保护来自 enqueue()
的队列写访问。它总是可以执行,因为 QSemaphore::release()
永远不会阻塞。因此,dequeue()
和enqueue(int)
有很多机会同时执行,造成严重破坏。
您现在拥有的信号量的作用是向队列的消费者端发送信号,告知队列中存在的值的数量。您将需要第二个 QSemaphore
来实现对底层 QQueue
的独占访问,如下(非常肤浅的测试):
#include <QThread>
#include <QQueue>
#include <QSemaphore>
class AsyncQueue
{
public:
void enqueue(const int x);
int dequeue();
private:
QQueue<int> queue;
QSemaphore itemsInQueue;
QSemaphore exclusiveAccess{1};
};
int AsyncQueue::dequeue()
{
itemsInQueue.acquire();
exclusiveAccess.acquire();
int result{queue.dequeue()};
exclusiveAccess.release();
return result;
}
void AsyncQueue::enqueue(const int x)
{
exclusiveAccess.acquire();
queue.enqueue(x);
exclusiveAccess.release();
itemsInQueue.release();
}
如果您可以使用现代编译器,我更愿意使用 STL 对应物来实现它。 std::thread
, std::mutex
, std::lock_guard
, and std::condition_variable
在这方面值得研究。
我想你可以按照下面的方法试试。
基本上文档说:
QSharedPointer and QWeakPointer are thread-safe and operate atomically on the pointer value. Different threads can also access the QSharedPointer or QWeakPointer pointing to the same object at the same time without need for locking mechanisms.
所以你不需要锁定机制.....
如何:?
using sInt = QSharedPointer<int>;
QQueue<sInt> qInt; //Your queue of shared pointer objects.
qInt.enqueue(QSharedPointer<int>::create(5));
qInt.enqueue(QSharedPointer<int>::create(6));
qInt.enqueue(QSharedPointer<int>::create(7));
qInt.enqueue(QSharedPointer<int>::create(8));
//To retrieve the value use either data() or get() as shown below.
sInt value = qInt.dequeue();
int *val = value.data();