我知道std::list
不是线程安全的。在我的应用程序线程中,不断添加元素到全局列表。另一个线程从列表中获取元素并逐个处理它们。但是,我不希望处理线程在处理过程中始终锁定列表。
因此处理线程锁定列表,获取元素,解锁列表并处理元素。在处理过程中,其他线程不断向列表中添加元素。处理完成后,处理线程再次锁定列表删除已处理的元素并将其解锁。
以下是伪代码:
std::list<int> mylist ; /* Global list of integers */
void add_thread(int element) /* Threads adding element to the list */
{
write_lock();
mylist.push_back(element);
write_unlock();
return;
}
void list_processing_thread() /* Processes elements from the list */
{
for (std::list<int>::iterator it=mylist.begin(); it!=mylist.end(); ++it)
{
read_lock();
int element = *it;
read_unlock();
process_element(element);
write_lock();
mylist.remove(element);
write_unlock();
}
return;
}
这是正确的方法(以有效的方式处理列表元素)吗?会不会有麻烦?
答案 0 :(得分:1)
因此处理线程锁定列表,获取元素,解锁列表并处理元素。在处理过程中,其他线程不断向列表中添加元素。处理完成后,处理线程再次锁定列表删除已处理的元素并将其解锁。
生产者线程相互竞争,并与消费者线程争用以访问列表。
您可以通过为每个生产者提供自己的队列(std :: list + std :: mutex或spinlock)来消除生产者之间的争用。这样:
std::list
,然后锁定互斥锁,将该元素拼接到队列中,解锁互斥锁。std::list
是O(1)操作。上述方法也会使你的关键部分变得非常短,因为在互斥锁被锁定时所做的只是std::list
拼接,这只是一些指针修改。
或者,只需使用英特尔®线程构建模块中的concurrent_bounded_queue类。
答案 1 :(得分:0)
不,这不安全。是的,它会造成麻烦。 详细说明: 应该只有一个锁是写锁。读者不需要互相辩护。 在访问开始和结束迭代器之前,您需要在处理线程中获取锁,因为它们可能被写入线程损坏。获得锁定后,复制列表并释放锁定。完成处理后,获取锁定,然后编辑原始列表。 祝你好运
答案 2 :(得分:0)
在C ++ 11中,这可能是您的问题的解决方案,但您可以轻松地将其移植到C ++ - 03 + boost或您拥有的任何线程库:
std::deque<int> queue;
std::mutex mtx;
std::condition_variable ready;
void producer()
{
while (true)
{
int element = produce();
std::unique_lock<std::mutex> lock(mtx);
queue.push_back(element);
lock.unlock();
ready.notify_one();
}
}
void consumer()
{
while (true)
{
std::unique_lock<std::mutex> lock(mtx);
ready.wait(lock, [](){ ! queue.empty() });
int element = queue.front();
queue.pop_front();
lock.unlock();
consume(element);
}
}
答案 3 :(得分:0)
对于不同级别的性能,您可以做很多事情,但有两个非常简单:
在处理线程中使用std::list::swap将队列与空队列进行交换,这样如果锁争用正在减慢速度,至少你会得到所有积压的项目一击,最小化伤害
使用单作者/多读者锁定(例如posix_rwlock_rdlock等)
答案 4 :(得分:-1)
首先,方法很好,你应该锁定一小段时间,获取当前项目,解锁并处理项目,同时列表被解锁并可供其他线程使用。
但是,我建议您在列表未锁定时不依赖列表迭代器。迭代器是偷偷摸摸的,当添加/删除项目时,许多数据结构可能会破坏迭代器。
我建议你使用以下方法:
while(list.empty() == false)
{
lock();
int element = list.front();
list.pop_front();
unlock();
process(element);
}
最好!