从C ++中的线程读取main中的变量值

时间:2019-05-04 07:44:36

标签: multithreading c++11 thread-safety mutex

我需要一个线程在while循环中执行一个函数(例如递增一个int值)。在主要方面,我需要有一个执行某些功能的while循环(例如,for循环从0到5计数),然后读取线程中变量的当前值。无论main中发生了什么,线程都必须继续运行自己的while循环。但是,在main读取线程变量时,线程变量的值不得更改。

我想这个问题可以使用atomic解决。但是,这是一个玩具问题,其中线程中的变量为int。在我的实际问题中,线程变量是否为Eigen :: quaternionf或float [4]类型。因此,我需要确保从main读取时,整个Eigen :: quaternionf或float [4]保持恒定。

线程中的cout仅用于调试。如果代码在线程安全的情况下运行,则可以将其删除。我从另一篇文章中读到,以线程安全的方式使用cout可能需要使用互斥量在cout周围编写新的包装。我想避免它。

我主要关心的是在main中以正确的顺序读取变量。

我的代码失败(今天是我使用多线程的第一天),如下所示以及观察到的输出(选定的部分)。代码无法使用cout(乱码输出)保持输出的顺序。另外,我不确定主线程是否正确读取了线程变量。

#include <thread>
#include <mutex>
#include <iostream>

int i = 0;


void safe_increment(std::mutex& i_mutex)
{

    while(1)
    {

    std::lock_guard<std::mutex> lock(i_mutex);
    ++i;

    std::cout << "thread: "<< std::this_thread::get_id() << ", i=" << i << '\n';
    }

}

int main()
{
    std::mutex i_mutex;  

    std::thread t1(safe_increment, std::ref(i_mutex));


   while(1)
{
    for(int k =0; k < 5; k++)
    {
    std::cout << "main: k =" << k << '\n';
    }

    std::lock_guard<std::mutex> lock(i_mutex);
    std::cout << "main: i=" << i << '\n';
}
}

我得到的输出(选定部分)是

thread: 139711042705152, i=223893
thread: 139711042705152, i=223894
thread: 139711042705152, i=223895
main: i=223895
main: k =0
thread: main: k =1139711042705152
main: k =2
main: k =3
, i=main: k =4
223896
thread: 139711042705152, i=223897
thread: 139711042705152, i=223898



thread: 139711042705152, i=224801
thread: 139711042705152, i=224802
main: i=224802
main: k =0
main: k =1
thread: main: k =2
main: k =3
main: k =4
139711042705152, i=224803
thread: 139711042705152, i=224804
thread: 139711042705152, i=224805

2 个答案:

答案 0 :(得分:1)

i已与互斥体正确同步。做得好!显然,它会一直运行直到您强制将其停止,因此,当您找到更好的方法来结束执行时,请确保在线程上join

要解决此问题,您需要在std::cout上进行同步:

int main()
{
    std::mutex i_mutex;  

    std::thread t1(safe_increment, std::ref(i_mutex));

    while(1)
    {
        std::lock_guard<std::mutex> lock(i_mutex);//moved up here to sync on std::cout << k
        for(int k =0; k < 5; k++)
        {
            std::cout << "main: k =" << k << '\n';
        }

        std::cout << "main: i=" << i << '\n';
        if (i > 100) break;
    }

    t1.join(); //thread will continue and main will wait until it is done
    //your thread needs to have some way out of its while(1) as well.
}

线程可能是这样的:

void safe_increment(std::mutex& i_mutex)
{
    while(1)
    {

    std::lock_guard<std::mutex> lock(i_mutex);
    ++i;

    std::cout << "thread: "<< std::this_thread::get_id() << ", i=" << i << '\n';
    if (i > 111) break;
    }

}

答案 1 :(得分:0)

这是一个基于异步和原子的命题:

#include <future>
#include <iostream>
#include <atomic>

std::atomic<int> i{0};
std::atomic<bool> stop{false};

void safe_increment()
{
    while (!stop)
    {
        ++i;
        std::cout << "thread: "<< std::this_thread::get_id() << ", i=" << i << '\n';
    }
}

int main()
{
    auto task = std::async(std::launch::async, safe_increment);

    while(1)
    {
        for(int k =0; k < 5; k++)
        {
            std::cout << "main: k =" << k << '\n';
        }

        std::cout << "main: i=" << i << '\n';

        if (i > 5000) {
            stop = true;
            break;
        }
    }

    task.get();
}

它不完全等同于您的代码,因为在stdout操作期间没有锁定,但是我认为这些争用并不是故意的。