此代码是从向量中添加和删除项目的线程安全方式吗?

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 事……就去做。线程在这里对您没有帮助。 “我不知道为什么会这样?” 因为这就是线程的作用!!!它使事情同时发生 老实说,当你甚至不知道线程是什么的时候,你为什么还要使用它们? 正如我之前所说的“我正在努力理解线程安全”。但是你是对的,这个例子的实现方法应该是先加项再删除项,而不是全部加项再删除所有项。

以上是关于此代码是从向量中添加和删除项目的线程安全方式吗?的主要内容,如果未能解决你的问题,请参考以下文章

单插入多读取列表是否安全无锁?

C++ 中的标准输出流是线程安全的(cout、cerr、clog)吗?

java.util.Vector 序列化线程安全吗?

从向量中删除已完成的线程

Java 正则表达式线程安全吗?

从C ++ 11线程安全地向向量添加元素