此代码是从向量中添加和删除项目的线程安全方式吗?
Posted
技术标签:
【中文标题】此代码是从向量中添加和删除项目的线程安全方式吗?【英文标题】:Is this code a thread-safe way to add and remove items from a vector? 【发布时间】:2020-10-03 19:28:43 【问题描述】:我试图很好地理解线程安全,所以,我有一个简单的代码(代码不是真实的),我已经应用了线程安全,如下所示:
vector<int> myList;
const unsigned short ListSize = 5;
mutex mut;
condition_variable cond;
void AddItem()
for (int i = 0; i < ListSize + 2; i++)
mut.lock();
myList.push_back(i);
mut.unlock();
cond.notify_one();
cout << "An item added." << "\n";
this_thread::sleep_for(chrono::milliseconds(300));
void RemoveItem()
for (int i = 0; i < ListSize; i++)
unique_lock<mutex> locker(mut);
cond.wait(locker, []() return !myList.empty(); );
myList.erase(myList.begin());
cout << "An item removed." << "\n";
this_thread::sleep_for(chrono::milliseconds(300));
int main()
thread th_task1(&AddItem);
thread th_task2(&RemoveItem);
th_task1.join();
th_task2.join();
if (!myList.empty())
cout << "There are " << myList.size() << " items." << "\n";
else
cout << "The list is empty." << "\n";
return 0;
另外,您可以测试来自here 的代码。
该代码是否被认为是线程安全的?如果不是如何使其成为线程安全的?
【问题讨论】:
随机想法。 cout 上有一个额外的锁争用可能会影响性能。循环可能运行时间太短而无法显示问题。抱着锁睡觉模拟大工作,这是你要测试的吗?创建线程的时间并非无关紧要,您可能希望从 mut 锁定开始并在创建两个线程后解锁它。谁可以使用互斥锁是否公平? @Surt:谢谢你的想法。关于使用std::cout
和 sleep 它们只是为了测试。 (1)以锁定mut
启动功能并在功能结束时解锁它是一种好方法,还是我必须锁定/解锁只是添加/删除项目的部分? (2) 当使用输入/输出流(std::cin
, std::cout
)时,是否也需要使用锁定/解锁?
【参考方案1】:
它是线程安全的(例如,你应该在应该锁定的时候锁定,并正确地执行wait
),但它不是一个很好的线程使用,因为你只会在添加线程完全完成时通知删除线程。
所以你也可以直接从main
拨打AddItem()
然后RemoveItem()
。
另外,虽然我知道休眠只是为了试验,但您可能需要考虑将这些休眠从锁中取出,否则,您再次创建大量争用,从而阻止多线程在任何方面都有用。
【讨论】:
关于解除睡眠进程的锁,当我这样做时,在第一次添加操作之后会发生一个删除操作,尽管它必须先执行所有添加操作,然后再执行移除操作。我不知道为什么会这样?看看这个screenShot @LionKing “它必须先执行所有添加操作,然后执行删除操作” 那你为什么使用两个线程?这不是线程的用途。如果你想做 A 事,那么 B 事……就去做。线程在这里对您没有帮助。 “我不知道为什么会这样?” 因为这就是线程的作用!!!它使事情同时发生。 老实说,当你甚至不知道线程是什么的时候,你为什么还要使用它们? 正如我之前所说的“我正在努力理解线程安全”。但是你是对的,这个例子的实现方法应该是先加项再删除项,而不是全部加项再删除所有项。以上是关于此代码是从向量中添加和删除项目的线程安全方式吗?的主要内容,如果未能解决你的问题,请参考以下文章