我有 2 个线程和全局队列,一个线程 (t1) 推送数据,另一个线程 (t2) 弹出数据,我想在不使用函数的情况下同步此操作,我们可以使用 Windows API 将该队列与临界区一起使用。
Queue是全局的,我想知道如何同步,是通过Queue的锁定地址来完成的吗?
是否可以使用 Boost Library 来解决上述问题?
我有 2 个线程和全局队列,一个线程 (t1) 推送数据,另一个线程 (t2) 弹出数据,我想在不使用函数的情况下同步此操作,我们可以使用 Windows API 将该队列与临界区一起使用。
Queue是全局的,我想知道如何同步,是通过Queue的锁定地址来完成的吗?
是否可以使用 Boost Library 来解决上述问题?
一种方法是有两个队列而不是一个:
唯一的锁定/阻塞/同步发生在交换队列时,这应该是一个快速的操作,因为它实际上是交换两个指针的问题。
我认为您可以在不使用任何原子或任何线程安全的东西的情况下创建一个具有这些条件的队列?
就像它只是一个圆形缓冲区一样,一个线程控制读取指针,另一个控制写入指针。在完成阅读或写作之前,两者都不会更新。它只是有效吗?
唯一的困难在于确定何时 read==write 队列是满的还是空的,但是您可以通过始终在队列中保留一个虚拟项目来克服这个问题
class Queue
{
volatile Object* buffer;
int size;
volatile int readpoint;
volatile int writepoint;
void Init(int s)
{
size = s;
buffer = new Object[s];
readpoint = 0;
writepoint = 1;
}
//thread A will call this
bool Push(Object p)
{
if(writepoint == readpoint)
return false;
int wp = writepoint - 1;
if(wp<0)
wp+=size;
buffer[wp] = p;
int newWritepoint = writepoint + 1;
if(newWritepoint==size)
newWritePoint = 0;
writepoint = newWritepoint;
return true;
}
// thread B will call this
bool Pop(Object* p)
{
writepointTest = writepoint;
if(writepointTest<readpoint)
writepointTest+=size;
if(readpoint+1 == writepoint)
return false;
*p = buffer[readpoint];
int newReadpoint = readpoint + 1;
if(newReadpoint==size)
newReadPoint = 0;
readpoint = newReadPoint;
return true;
}
};
处理此问题的另一种方法是动态分配队列并将其分配给指针。当项目必须出列时,指针值在线程之间传递,并且您使用临界区保护此操作。这意味着每次推送到队列时都会锁定,但对删除项目的争用要少得多。
当您在入队和出队之间有很多项目时,这很有效,而在项目很少的情况下效果较差。
示例(我正在使用一些给定的 RAII 锁定类来进行锁定)。另请注意...只有当只有一个线程出队时才真正安全。
queue* my_queue = 0;
queue* pDequeue = 0;
critical_section section;
void enqueue(stuff& item)
{
locker lock(section);
if (!my_queue)
{
my_queue = new queue;
}
my_queue->add(item);
}
item* dequeue()
{
if (!pDequeue)
{ //handoff for dequeue work
locker lock(section);
pDequeue = my_queue;
my_queue = 0;
}
if (pDequeue)
{
item* pItem = pDequeue->pop(); //remove item and return it.
if (!pItem)
{
delete pDequeue;
pDequeue = 0;
}
return pItem;
}
return 0;
}