首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >C++代码显然是按顺序执行的

C++代码显然是按顺序执行的
EN

Stack Overflow用户
提问于 2021-11-08 02:11:14
回答 1查看 82关注 0票数 0
  • The code

这是一个使用WiringPi的Raspberry Pi项目。我有一个模板类的以下三个成员函数,以及用于read()write()的纯虚拟化。然后,这个基类由提供read()write()函数的更专门的类子类(示例如下所示):

代码语言:javascript
运行
复制
// IChip.hpp (Root abstract class)
class IChip {
    public:
    virtual bool test() noexcept = 0;
};
// End IChip.hpp

// IMemory.hpp (class of interest to the question)
class IMemory: public IChip {
    protected:
    ...
    TAddr m_wordCount;
    TWord m_dataMax;
    // ctor and dtor, and more member fields

    public:
    virtual TWord read(const TAddr addr) const noexcept = 0;
    virtual void write(const TAddr addr, const TWord data) const noexcept = 0;

    // accessors and whatnot ...

    bool march(bool keepGoing = false) noexcept;
    bool checkerboard(bool keepGoing = false) noexcept;

    bool test() noexcept final override;
};
// End IMemory.hpp


// IMemory.cpp
template <typename TAddr, typename TWord>
bool IMemory<TAddr, TWord>::march(bool keepGoing) noexcept {
    bool result = true;
    TAddr i;
    TWord r;
    const uint64_t totalIter = (m_wordCount * 6) - 1;
    uint64_t counter = 0;

    std::cout << "Starting MARCH test." << std::endl;

    for (i = 0; i < m_wordCount; i++) {
        this->write(i, 0);
        std::cout << '\r' << counter << " / " << totalIter << std::flush;
        counter++;
    }

    for (i = 0; i < m_wordCount; i++) {
        r = this->read(i);
        if (r != 0) {
            result = false;
            if (!keepGoing)
                return result;
        }
        this->write(i, m_dataMax);
        std::cout << '\r' << counter << " / " << totalIter << std::flush;
        counter++;
    }

    // 4 more similar loops

    std::cout << std::endl;

    std::cout << "MARCH test done." << std::endl;

    return result;
}

template <typename TAddr, typename TWord>
bool IMemory<TAddr, TWord>::checkerboard(bool keepGoing) noexcept {
    bool result = true;
    TAddr i;
    TWord r;
    TWord curWord;
    const uint64_t totalIter = (m_wordCount * 4) - 1;
    uint64_t counter = 0;

    std::cout << "Starting CHECKERBOARD test." << std::endl;

    curWord = 0;
    for (i = 0; i < m_wordCount; i++) {
        this->write(i, curWord);
        std::cout << '\r' << counter << " / " << totalIter << std::flush;
        counter++;
        curWord = curWord == 0 ? m_dataMax : 0;
    }

    curWord = 0;
    for (i = 0; i < m_wordCount; i++) {
        r = this->read(i);
        if (r != curWord) {
            result = false;
            if (!keepGoing)
                return result;
        }
        std::cout << '\r' << counter << " / " << totalIter << std::flush;
        counter++;
        curWord = curWord == 0 ? m_dataMax : 0;
    }

    // 2 more similar loops ...

    std::cout << std::endl;
    std::cout << "CHECKERBOARD test done." << std::endl;

    return result;
}

template <typename TAddr, typename TWord>
bool IMemory<TAddr, TWord>::test() noexcept {
    bool march_result = this->march();
    bool checkerboard_result = this->checkerboard();
    bool result = march_result && checkerboard_result;

    std::cout << "MARCH: " << (march_result ? "Passed" : "Failed") << std::endl;
    std::cout << "CHECKERBOARD: " << (checkerboard_result ? "Passed" : "Failed") << std::endl;
    return result;
}

// Explicit instantiation
template class IMemory<uint16_t, uint8_t>;
// End IMemory.cpp


// Sample read() and write() from HM62256, a subclass of IMemory<uint16_t, uint8_t>
// These really just bitbang onto / read data from pins with appropriate timings for each chip.
// m_data and m_address are instances of a Bus class, that is just a wrapper around an array of pins, provides bit-banging and reading functionality.

uint8_t HM62256::read(uint16_t addr) const noexcept {
    uint8_t result = 0;

    m_data->setMode(INPUT);
    m_address->write(addr);
    digitalWrite(m_CSPin, LOW);
    digitalWrite(m_OEPin, LOW);
    delayMicroseconds(1);
    result = m_data->read();
    digitalWrite(m_OEPin, HIGH);
    digitalWrite(m_CSPin, HIGH);
    delayMicroseconds(1);
    return result;
}

void HM62256::write(uint16_t addr, uint8_t data) const noexcept {
    digitalWrite(m_OEPin, HIGH);
    delayMicroseconds(1);

    m_address->write(addr);
    delayMicroseconds(1);

    m_data->setMode(OUTPUT);
    m_data->write(data);

    digitalWrite(m_CSPin, LOW);
    digitalWrite(m_WEPin, LOW);
    delayMicroseconds(1);

    digitalWrite(m_WEPin, HIGH);
    digitalWrite(m_CSPin, HIGH);
    delayMicroseconds(1);
}

// main.cpp
void hm62256_test() {
    const uint8_t ADDR_PINS[] = {4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18};
    const uint8_t DATA_PINS[] = {19, 20, 21, 22, 23, 24, 25, 26};
    Chiptools::Memory::HM62256 *device = new Chiptools::Memory::HM62256(ADDR_PINS, DATA_PINS, 2, 3, 27);

    device->setup();
    bool result = device->test();
    std::cout << "Device " << ( result ? "passed all" : "failed some") << " tests." << std::endl;
    delete device;
}

int main(int argc, char *argv[]) {
    wiringPiSetupGpio();
    hm62256_test();
}

  • The output

现在,当我运行这个程序时,它有时工作得很好:

代码语言:javascript
运行
复制
Starting MARCH test.
196607 / 196607
MARCH test done.
Starting CHECKERBOARD test.
131071 / 131071
CHECKERBOARD test done.
MARCH: Passed
CHECKERBOARD: Passed
Device passed all tests.

但是随机地,我会得到这个输出:

代码语言:javascript
运行
复制
Starting MARCH test.
67113 / 196607Starting CHECKERBOARD test.
33604 / 131071MARCH: Failed
CHECKERBOARD: Failed
Device failed some tests.

  • Toolchain info
    • gcc 8.3.0 arm-linux / C++14
    • Cmake 3.16.3
    • No threading.
    • Compiler & Linker flags:

代码语言:javascript
运行
复制
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -fsanitize=address,leak,undefined")
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fsanitize=address,leak,undefined  -static-libasan")

  • The问题与我tried

我有几十块薯片。所有的芯片与TL866ii程序员/测试人员一起工作得很好。所有这些芯片都会发生这种情况。所以这就排除了芯片是问题的根源。

首先,我想我可能没有正确地刷新cout流,但是AFAIK std::endl确实刷新了输出,所以不是这样的。

接下来,我设置了几个断点:(A)在march()返回之前,(B)在调用checkerboard()的位置(test()中的第2行),(C)在checkerboard()内的第一行。

当输出与预期相同时,按以下顺序命中断点: C.

  • When A、B、输出与预期不同,断点按B、C、A.顺序命中

它看起来正在发生的情况是,有时在checkerboard()仍在运行时调用march(),导致随机的GPIO输出,此时一个测试或两个测试都失败。

当我在寻找解决这个问题的方法时,我更感兴趣的是对正在发生的事情的一些洞察力。我认为,由于我的代码没有使用多线程,而且根据我对C++标准的理解,在执行下一个语句之前,语句会一个一个地执行到完成。我知道有些编译器实现会为优化重新排序语句,但是AFAIK不应该影响代码的语义。我可能错了,因为那些东西远远超出了我的想象。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2021-11-08 02:41:14

这可能不是一个答案,但它太长,不能发表评论。

在“三月测试完成”行之后,A是否在return语句中?

以下是基于这一输出的评论:

代码语言:javascript
运行
复制
Starting MARCH test.
67113 / 196607Starting CHECKERBOARD test.
33604 / 131071MARCH: Failed
CHECKERBOARD: Failed
Device failed some tests.

看起来正在发生的情况是,您的三月测试在第三个循环中失败,因此提前返回(在循环内)。然后,您的Checkerboard测试在第二个循环中失败,并且也会提前返回。如果A处于我提到的位置,那么我认为命中这个断点只是运气或编译器的怪癖。

也就是说,从逻辑上说,当故障发生时,我完全不希望断点A被击中,只有BC。我认为,A最终被击中的原因可能是它是如何编译程序的,也许还有一些奇怪的优化。也可能是在程序集中调试器放置断点的位置;它可能只是在最终指令上,无论如何都会被调用。尝试将断点放在std::cout行的return之前,看看它是否仍被击中。

为了扩展您的评论,我在问题输出中看到了以下内容:

代码语言:javascript
运行
复制
Starting MARCH test.
67113 / 196607 [march() returns early] [checkerboard() starts] Starting CHECKERBOARD test.
33604 / 131071 [checkerboard() returns early] [test() reports results] MARCH: Failed
CHECKERBOARD: Failed
Device failed some tests.

总之,我认为如果您更改返回线,输出将与您的预期相匹配:

代码语言:javascript
运行
复制
if (!keepGoing) 
    return result; 

像这样的事情:

代码语言:javascript
运行
复制
if (!keepGoing) {
    std::cout << std::endl;
    std::cout << "MARCH test failed." << std::endl;
    return result;
}

我希望它能产生这样的产出:

代码语言:javascript
运行
复制
Starting MARCH test.
67113 / 196607
MARCH test failed
Starting CHECKERBOARD test.
33604 / 131071
CHECKERBOARD test failed
MARCH: Failed
CHECKERBOARD: Failed
Device failed some tests.
票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/69878022

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档