【问题标题】: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)时,是否也需要使用锁定/解锁?

标签: c++ multithreading thread-safety


【解决方案1】:

它是线程安全的(例如,你应该在应该锁定的时候锁定,并正确地执行wait),但它不是一个很好的线程使用,因为你只会在添加线程完全完成时通知删除线程。

所以你也可以直接从main 拨打AddItem() 然后RemoveItem()

另外,虽然我知道休眠只是为了试验,但您可能需要考虑将这些休眠从锁中取出,否则,您再次创建大量争用,从而阻止多线程在任何方面都有用。

【讨论】:

  • 关于解除睡眠进程的锁,当我这样做时,在第一次添加操作之后会发生一个删除操作,尽管它必须先执行所有添加操作,然后再执行移除操作。我不知道为什么会这样?看看这个screenShot
  • @LionKing “它必须先执行所有添加操作,然后执行删除操作” 那你为什么使用两个线程?这不是线程的用途。如果你想做 A 事,那么 B 事……就去做。线程在这里对您没有帮助。 “我不知道为什么会这样?” 因为这就是线程的作用!!!它使事情同时发生
  • 老实说,当你甚至不知道线程是什么的时候,你为什么还要使用它们?
  • 正如我之前所说的“我正在努力理解线程安全”。但是你是对的,这个例子的实现方法应该是先加项再删除项,而不是全部加项再删除所有项。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-02-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-05-18
相关资源
最近更新 更多