【问题标题】:Understanding Variable Accessibility in Threads了解线程中的变量可访问性
【发布时间】:2017-09-21 07:22:00
【问题描述】:

我试图更好地理解线程中的变量访问。经过一番研究,我发现了很多关于atomic的信息,效果很好!不过,我已经停滞不前了,希望有人帮助我继续前进。

设置:

  • 我有两个类 - 一个类从文本文件中读取以获取上次启动的信息以及每次启动所需的其他信息。这是一个单独的课程,仅用于组织。读取的信息存储在原子变量中。

  • 另一个类具有我的所有功能。这包括读取用于存储来自信息文件的信息的变量的变量。简单地说,这个类继承了第一个类保存那个信息文件的变量。

  • 主函数在代码的最开始一起创建类对象,因为我需要类中的函数用于程序的其他部分。在初始设置(包括读取该信息文件)之后,它会从需要为程序的其余部分运行的第二类函数创建线程

问题:

为什么第二类函数的线程不能读取它从第一类继承的信息?

  • 我在创建线程之前很久就开始阅读了。可能是因为第二个类继承了原始变量(它们都被初始化为 0),因为我在执行读取信息文件功能之前声明了它?
  • 主函数中的变量读取良好。

.

#include "stdafx.h"
#include "Windows.h"
#include <iostream>
#include <thread>
#include <atomic>

std::atomic<bool> timeToClose = false;

class first {
public:
    std::atomic<int> primary;
    void readFile() {
        primary = 1;
    }
    first() {
        primary = 0;
    }
};

class second: first {
public:
    void actionPrimary() {
        while (!timeToClose) {
            if (primary) {
                std::cout << "We ARE doing stuff here!\n";
                std::this_thread::sleep_for(std::chrono::milliseconds(1500));
            } else {
                std::cout << "We AREN'T doing stuff here!\n";
                std::this_thread::sleep_for(std::chrono::milliseconds(1500));
            }
        }
    }
};

int main() {
    first f;
    second s;
    f.readFile();
    std::thread threadActionPrimary([&s]() {
        s.actionPrimary();
    });
    while (!GetAsyncKeyState(VK_F1)) {
        std::this_thread::sleep_for(std::chrono::milliseconds(100));
    }
    timeToClose = true;
    threadActionPrimary.join();
    std::cin.get();
}

编辑到凹凸 :)

【问题讨论】:

  • 欢迎来到 Stack Overflow。你已经尝试过什么来做到这一点?请查看How much research effort is expected?。 Stack Overflow 不是编码服务。您应该在发布之前研究您的问题并尝试自己编写代码。如果您遇到特定问题,请返回并附上Minimal, Complete, and Verifiable example 和您尝试过的内容的摘要,以便我们提供帮助。
  • 我查看了几十个其他线程(它们也在堆栈溢出中),但它们都只是模糊相关。我想我会提出自己的问题。我尝试更改变量的读取方式、变量数据类型、存储方式、线程的创建方式以及格式(如 lambda 和诸如此类)、不同的线程继承等。抱歉,如果问题没有看起来很有信息量,我将添加一个最小、完整和可验证的示例。
  • 将文件信息存入变量后,这些变量会被修改吗?
  • @Sand Done :-)
  • 我不确定我是否明白了你的意图。在main() 中,您有一个实例first f; 和另一个second s;。然后你打电话给f.readfile();。然后您参考s 启动一个线程。您是否期望s 包含f 的数据?尽管s 属于second 类,它继承自firstf 的类),但每个实例都有自己的数据。 std::atomic&lt;&gt; 不会改变这一点。如果您将first::primary 设为static 成员那么 它会改变。

标签: c++ multithreading variables atomic


【解决方案1】:

线程 a 中的项目何时对线程 b 可见。

这与cppreference : memory_order 有关。更改对第二个线程可见。

  • 线程 A 写入原子值(使用 std::atomic
  • 线程B读取原子值(使用std::atomic

还有一些与同步相关的更复杂的版本。

  • 线程 A 写入一些数据。
  • 线程 A 使用互斥锁或写入 std::atomic
  • 线程 B 使用互斥锁或从 std::atomic 读取
  • 线程 B 可以看到从线程 A 到其同步点的所有内存更改。

在这种情况下实际发生的是类变量中的实例数据。

class MyBase {
    public:
       int BaseValue;
       MyBase() : BaseValue(10);
       void setValue( int v ) {
           BaseValue = v;
       }
};

class MyDerived : public MyBase {
      MyDerived() {}
};

 MyBase base;
 base.setValue( 12 );
 MyDerived derived;
 // derived.BaseValue = 10;
 // base.BaseValue = 12;  <<<< There are 2 different instances of the member BaseValue.

更新

每次创建变量时;

int i = 5;
int j = 10;

您创建了一个新的“容器”。如果您希望两个线程使用其中一个类 (second?) 进行通信,您需要创建一个容器,那么数据应该是可见的。

但是,要使其正常工作,您需要在 2 个线程之间进行某种形式的同步。

int main() {
    second s;
    s.readFile();
    std::thread threadActionPrimary([&s]() { // this acts as a synchronization point, so the thread sees all the changes to s that happened before this line.
        s.actionPrimary();
    });
    while (!GetAsyncKeyState(VK_F1)) {
        std::this_thread::sleep_for(std::chrono::milliseconds(100));
    }
    timeToClose = true;
    threadActionPrimary.join();
    std::cin.get();
}

【讨论】:

  • 对,这解释了它,但我能做些什么来真正使实例同步?
  • 另外,您的输入“v”似乎什么也没做。运行 setValue 后 BaseValue = 5
猜你喜欢
  • 1970-01-01
  • 2011-04-03
  • 2017-08-11
  • 1970-01-01
  • 1970-01-01
  • 2019-01-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多