【问题标题】:Two threads sharing variable C++两个线程共享变量 C++
【发布时间】:2016-02-09 00:24:07
【问题描述】:

所以我有两个线程,它们共享同一个变量“计数器”。我想通过仅在两个线程都达到该点后继续执行来同步我的线程。不幸的是,我进入了死锁状态,因为我的线程没有改变它的检查变量。我的方法是:

volatile int counter = 0;

    Thread() {

             - some calculations - 

            counter++;
            while(counter != 2) {
               std::this_thread::yield();
            }
            counter = 0;

            - rest of the calculations -
    }

这个想法是,由于我有 2 个线程,一旦它们到达那个点 - 在不同的时间 - 它们将增加计数器。如果计数器不等于 2,那么首先到达那里的线程将不得不等待,直到另一个线程增加了计数器,以便它们同步。有谁知道问题出在哪里?

为了添加有关该问题的更多信息,我有两个线程在数组上执行一半的操作。一旦他们完成,我想确保他们都完成了他们的计算。一旦它们是,我可以通知打印机线程唤醒并执行它的打印和清除阵列的操作。如果我在两个线程完成之前这样做,就会出现问题。

伪代码:

Thread() {

    getLock()
    1/2 of the calculations on array
    releaseLock()

    wait for both to finish - this is the issue

    wake up printer thread

}

【问题讨论】:

  • 通常当我们谈论线程同步时,我们谈论的是强制线程一个接一个地按顺序运行,而不是at同一时间。你似乎试图做相反的事情。你能解释一下为什么你想让你的线程同时运行吗?顺便说一句,无法确定您的线程是否会同时运行,这取决于操作系统调度程序。
  • 所以本质上我正在对一个数组执行计算,该数组在两个线程之间拆分。最后,我想使用另一个线程打印和清除这个数组。我需要一个线程来唤醒打印线程,但我需要两个线程都在阵列上完成它们的执行,然后才能唤醒打印机线程。如果它们不同步,我会得到一个未完成的数组。
  • volatile 在多线程中没有地位

标签: c++ multithreading synchronization atomic stdatomic


【解决方案1】:

我会考虑使用倒计时锁存器。这个想法是让一个或多个线程阻塞,直到所需的操作完成。在这种情况下,您希望等到两个线程都完成对数组的修改。

这是一个简单的例子:

#include <condition_variable>
#include <mutex>
#include <thread>

class countdown_latch
{
public:
    countdown_latch(int count)
        : count_(count)
    {
    }

    void wait()
    {
        std::unique_lock<std::mutex> lock(mutex_);
        while (count_ > 0)
            condition_variable_.wait(lock);
    }

    void countdown()
    {
        std::lock_guard<std::mutex> lock(mutex_);
        --count_;
        if (count_ == 0)
            condition_variable_.notify_all();
    }

private:
    int count_;
    std::mutex mutex_;
    std::condition_variable condition_variable_;
};

用法如下所示

std::atomic<int> result = 0;
countdown_latch latch(2);

void perform_work()
{
    ++result;
    latch.countdown();
}

int main() 
{
    std::thread t1(perform_work);
    std::thread t2(perform_work);

    latch.wait();

    std::cout << "result = " << result;

    t1.join();
    t2.join();
}

【讨论】:

    【解决方案2】:

    您可能正在寻找std::conditional_variable:条件变量允许一个线程向另一个线程发出信号。因为它看起来不像您在使用计数器,而只是将其用于同步,所以这里是来自 another answer 的一些代码(免责声明:这是我的答案之一),它显示了 std::conditional_variable 在不同线程上的处理逻辑,并围绕一个值执行同步:

    unsigned int accountAmount;
    std::mutex mx;
    std::condition_variable cv;
    
    void depositMoney()
    {
        // go to the bank etc...
        // wait in line...
        {
            std::unique_lock<std::mutex> lock(mx);
            std::cout << "Depositing money" << std::endl;
            accountAmount += 5000;
        }
        // Notify others we're finished
        cv.notify_all();
    }
    void withdrawMoney()
    {
        std::unique_lock<std::mutex> lock(mx);
        // Wait until we know the money is there
        cv.wait(lock);
        std::cout << "Withdrawing money" << std::endl;
        accountAmount -= 2000;
    }
    int main()
    {
        accountAmount = 0;
        // Run both threads simultaneously:
        std::thread deposit(&depositMoney);
        std::thread withdraw(&withdrawMoney);
        // Wait for both threads to finish
        deposit.join();
        withdraw.join();
        std::cout << "All transactions processed. Final amount: " << accountAmount << std::endl;
        return 0;
    }
    

    【讨论】:

    • 我相信这个方法非常类似于 cond_wait/cond_signal 类型的实现。由于两个线程具有相同的功能,我不确定是否可以使用这样的实现,如果添加等待调用,则两者都将开始等待。
    • 类似,但另一种方法是拥有两个这种类型的对象,并在它们的父级(逻辑意义上)中有一个条件变量,waits 直到计数器正确。
    【解决方案3】:

    在这种情况下,您必须使用原子计数器。

    std::atomic_uint counter = 0;
    

    在给定的示例中,也没有迹象表明 counter 已初始化。

    【讨论】:

    • 我已经使用volatile int counter = 0; 对其进行了初始化,但您能帮我了解如何使用原子计数器吗?
    • atomics 是 C++11 处理此问题的方法,而将 volatile 留给硬件接口。 en.cppreference.com/w/cpp/atomic 另一个问题是 yield 只是一个提示。你可能想要sleep。我在下面有一条评论可能也会有所帮助。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-08-14
    • 2018-08-28
    • 2017-09-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多