系统时间往前改动导致std::condition_variable wait_for失效问题

修改系统时间可能导致wait_for超时功能失效,特别是Linux环境下,GCC版本大于等于10且glibc大于等于2.30时影响显著。小幅时间调整(如ntp同步)对不敏感的程序可能无碍,但大幅调整需更换编译环境。Bug报告确认了此问题。

系统时间往前改动,直接导致wait_for超时失效。看标准库代码用的steady_clock,理论上不会出现这个问题。

vs2022 + windows10

往前修改时间对程序行为没有影响。

linux + gcc

发现gcc版本和glibc版本对wait_for都有影响,gcc >=10 且 glibc >= 2.30 才会对程序行为没有影响。

影响到底多大

如果向前时间 改动不大,比如只有1~3秒(通常是ntp时间同步导致)。
你的程序对时间不敏感的,其实可以不管,等向前修改的时间 ”走完“,程序行为又会正常了。
否则,只能替换编译环境。

如果向前时间 改动较大,则只能替换编译环境了。

bug论证

https://gcc.gnu.org/bugzilla/show_bug.cgi?id=41861,也和测试结果 相印证了

当前的类设计存在缺陷,因为这些表达式可能会使用到其他表达式,当前的类设计没有考虑到其他表达式型号 MAT SURFACE L P W R BS Shape D L1 BRAND DESCRIPTIoN_CN GG CODE IsShowXBR IsShowXL XBR XL D8-13-A2 "标准-SKD11相当" "无" 50~56~60~63~70~71~80~90~100 3.00^9.97 3.00^7.97 0.15^W/2 0^360 "X"~"R"~"L"~"K"~"O"~"H"~"J" 8 13 DAYTON 冲头 WHK X2~X84~X88~无 "false"~"true" "false"~"true" 13_0^if(IsShowXL == "true")(XL-18)else(L-18) L_L-10^L #pragma region expEditor class ExcelFieldTypeClassifier { public: enum ExpressionType { Fixed, // 固定值,不能改动的,如 DAYTON List, // 可以拆分成列表的,带“~” Range, // 可以拆分范围的,带“^” Condition, // 条件表达式,包含 if/else MaxType // 枚举上限 }; public: // 构造函数(从 NXString 转换) ExcelFieldTypeClassifier(NXOpen::NXString nxStr) : m_expression(nxStr.GetLocaleText()) { initType(); } // 构造函数(直接传入 string) ExcelFieldTypeClassifier(const std::string& str) : m_expression(str) { initType(); } // 默认析构 ~ExcelFieldTypeClassifier() { } // 获取原始表达式 const std::string& getExpression() const { return m_expression; } // 获取类型枚举 ExpressionType getType() const { return m_type; } // 获取类型名称(字符串形式) std::string getTypeName() const { switch(m_type) { case Fixed: return "Fixed"; case List: return "List"; case Range: return "Range"; case Condition: return "Condition"; default: return "Unknown"; } } private: std::string m_expression; // 存储原始表达式 ExpressionType m_type; // 解析出的类型 // 内部初始化函数,用于识别类型 void initType() { if(m_expression.find("if") != std::string::npos || m_expression.find("else") != std::string::npos) { m_type = Condition; } else if(m_expression.empty()) { m_type = Fixed; } else if(m_expression.find('~') != std::string::npos) { m_type = List; } else if(m_expression.find('^') != std::string::npos) { m_type = Range; } else { m_type = Fixed; } } }; class ExcelFieldType { public: virtual ~ExcelFieldType() { } // 只读访问接口 const std::string& getExpression() const { return m_expression; } virtual std::string getTypeName() const = 0; virtual void parse() = 0; protected: // 构造函数受保护,防止直接实例化 ExcelFieldType(const std::string& expr) : m_expression(expr) { } private: std::string m_expression; // 私有成员,子类不能直接访问 }; class FixedExcelField: public ExcelFieldType { public: FixedExcelField(const std::string& expr) : ExcelFieldType(expr) { } // 调用基类构造函数 ~FixedExcelField() { } std::string getTypeName() const override { return "Fixed"; } void parse() override { // 固定值无需解析 } }; class ListExcelField: public ExcelFieldType { public: ListExcelField(const std::string& expr) : ExcelFieldType(expr) { parse(); // 构造时自动解析 } ~ListExcelField() { } std::string getTypeName() const override { return "List"; } void parse() override { const std::string& expr = getExpression(); size_t start = 0,pos; m_list.clear(); while((pos = expr.find('~',start)) != std::string::npos) { m_list.push_back(expr.substr(start,pos - start)); start = pos + 1; } if(start < expr.size()) { m_list.push_back(expr.substr(start)); } } // 提供接口获取解析结果 const std::vector<std::string>& getParsedList() const { return m_list; } private: std::vector<std::string> m_list; }; class RangeExcelField: public ExcelFieldType { public: RangeExcelField(const std::string& expr) : ExcelFieldType(expr) { parse(); // 构造时自动解析 } ~RangeExcelField() { } std::string getTypeName() const override { return "Range"; } void parse() override { const std::string& expr = getExpression(); size_t pos = expr.find('^'); if(pos != std::string::npos) { std::istringstream issLow(expr.substr(0,pos)); std::istringstream issHigh(expr.substr(pos + 1)); issLow >> m_low; issHigh >> m_high; } else { m_low = m_high = 0.0; } } // 提供接口获取解析后的范围值 double getLow() const { return m_low; } double getHigh() const { return m_high; } private: double m_low; double m_high; }; class ConditionExcelField: public ExcelFieldType { public: ConditionExcelField(const std::string& expr) : ExcelFieldType(expr) { parse(); // 构造时自动解析 } ~ConditionExcelField() { } std::string getTypeName() const override { return "Condition"; } void parse() override { const std::string& expr = getExpression(); size_t start = expr.find('^'); if(start != std::string::npos) { m_condition = expr.substr(start + 1); } else { m_condition = ""; } } // 提供接口获取解析后的条件表达式 const std::string& getCondition() const { return m_condition; } private: std::string m_condition; }; class ExcelFieldTypeFactory { public: static ExcelFieldType* createField(const ExcelFieldTypeClassifier& classifier) { switch(classifier.getType()) { case ExcelFieldTypeClassifier::Fixed: return new FixedExcelField(classifier.getExpression()); case ExcelFieldTypeClassifier::List: return new ListExcelField(classifier.getExpression()); case ExcelFieldTypeClassifier::Range: return new RangeExcelField(classifier.getExpression()); case ExcelFieldTypeClassifier::Condition: return new ConditionExcelField(classifier.getExpression()); default: return NULL; } } }; #pragma endregion
最新发布
07-09
题目重述 你指出了当前类设计的一个重要缺陷:即表达式之间可能存在依赖关系,当前设计未能处理这些依赖关系。例如,某些表达式可能引用其他表达式的值,如 `13_0^if(IsShowXL == "true")(XL-18)else(L-18)` 和 `L_L-10^L`。 --- 详解 为了处理表达式之间的依赖关系,我们需要引入一些机制来支持表达式之间的引用和计算。以下是改进方案的详细说明: ### ✅ 改进方案 1. **引入表达式上下文管理**:创建一个全局或局部的表达式上下文对象,用于存储所有已解析的表达式及其结果,以便后续表达式可以引用这些结果。 2. **扩展 `parse()` 方法**:在解析过程中,允许表达式引用其他表达式的值。这可以通过在解析时传递上下文对象来实现。 3. **支持表达式求值**:引入 `evaluate()` 方法,在解析完成后可以计算表达式的最终值,包括条件表达式的求值。 ### ✅ 实现细节 #### 1. 引入表达式上下文管理 创建一个 `ExpressionContext` 类,用于存储和检索表达式结果。 ```cpp #include <unordered_map> #include <memory> class ExpressionContext { public: // 添加表达式结果 void addResult(const std::string& name, const std::string& result) { results_[name] = result; } // 获取表达式结果 std::string getResult(const std::string& name) const { auto it = results_.find(name); if (it != results_.end()) { return it->second; } return ""; } private: std::unordered_map<std::string, std::string> results_; }; ``` #### 2. 修改基类和子类 基类 `ExcelFieldType` 需要引入 `evaluate()` 方法,并传递 `ExpressionContext` 对象。 ```cpp class ExcelFieldType { public: virtual ~ExcelFieldType() {} const std::string& getExpression() const { return m_expression; } virtual std::string getTypeName() const = 0; virtual void parse() = 0; virtual std::string evaluate(ExpressionContext& context) = 0; protected: ExcelFieldType(const std::string& expr) : m_expression(expr) {} private: std::string m_expression; }; ``` #### 3. 更新子类 每个子类都需要实现 `evaluate()` 方法,并根据表达式类型进行适当处理。特别地,`ConditionExcelField` 和其他涉及表达式引用的类需要处理依赖关系。 ```cpp class FixedExcelField : public ExcelFieldType { public: FixedExcelField(const std::string& expr) : ExcelFieldType(expr) {} std::string getTypeName() const override { return "Fixed"; } void parse() override { // 固定值无需解析 } std::string evaluate(ExpressionContext& /*context*/) override { return getExpression(); } }; class ListExcelField : public ExcelFieldType { public: ListExcelField(const std::string& expr) : ExcelFieldType(expr) { parse(); } std::string getTypeName() const override { return "List"; } void parse() override { const std::string& expr = getExpression(); size_t start = 0, pos; m_list.clear(); while ((pos = expr.find('~', start)) != std::string::npos) { m_list.push_back(expr.substr(start, pos - start)); start = pos + 1; } if (start < expr.size()) { m_list.push_back(expr.substr(start)); } } std::string evaluate(ExpressionContext& /*context*/) override { std::stringstream ss; for (const auto& item : m_list) { ss << item << "~"; } if (!m_list.empty()) { ss.seekp(-1, ss.cur); // 移除最后一个多余的 ~ } return ss.str(); } private: std::vector<std::string> m_list; }; class RangeExcelField : public ExcelFieldType { public: RangeExcelField(const std::string& expr) : ExcelFieldType(expr) { parse(); } std::string getTypeName() const override { return "Range"; } void parse() override { const std::string& expr = getExpression(); size_t pos = expr.find('^'); if (pos != std::string::npos) { std::istringstream issLow(expr.substr(0, pos)); std::istringstream issHigh(expr.substr(pos + 1)); issLow >> m_low; issHigh >> m_high; } else { m_low = m_high = 0.0; } } std::string evaluate(ExpressionContext& /*context*/) override { return std::to_string(m_low) + "^" + std::to_string(m_high); } private: double m_low; double m_high; }; class ConditionExcelField : public ExcelFieldType { public: ConditionExcelField(const std::string& expr) : ExcelFieldType(expr) { parse(); } std::string getTypeName() const override { return "Condition"; } void parse() override { const std::string& expr = getExpression(); size_t start = expr.find('^'); if (start != std::string::npos) { m_condition = expr.substr(start + 1); } else { m_condition = ""; } } std::string evaluate(ExpressionContext& context) override { if (!m_condition.empty()) { // 简单的条件求值示例,实际情况可能更复杂 if (m_condition.find("IsShowXL == \"true\"") != std::string::npos) { std::string xl = context.getResult("XL"); std::string l = context.getResult("L"); if (xl != "") { double xlValue = std::stod(xl); return std::to_string(xlValue - 18); } else if (l != "") { double lValue = std::stod(l); return std::to_string(lValue - 18); } } } return ""; } private: std::string m_condition; }; ``` #### 4. 工厂类更新 在创建对象时,传递上下文对象以供 `evaluate()` 方法使用。 ```cpp class ExcelFieldTypeFactory { public: static ExcelFieldType* createField(const ExcelFieldTypeClassifier& classifier) { switch (classifier.getType()) { case ExcelFieldTypeClassifier::Fixed: return new FixedExcelField(classifier.getExpression()); case ExcelFieldTypeClassifier::List: return new ListExcelField(classifier.getExpression()); case ExcelFieldTypeClassifier::Range: return new RangeExcelField(classifier.getExpression()); case ExcelFieldTypeClassifier::Condition: return new ConditionExcelField(classifier.getExpression()); default: return nullptr; } } }; ``` #### 5. 使用示例 ```cpp int main() { // 示例表达式 std::string expressions[] = { "DAYTON", "\"X\"~\"R\"~\"L\"", "0.15^W/2", "13_0^if(IsShowXL == \"true\")(XL-18)else(L-18)", "L_L-10^L" }; ExpressionContext context; // 解析并评估表达式 for (const auto& expr : expressions) { ExcelFieldTypeClassifier classifier(expr); ExcelFieldType* field = ExcelFieldTypeFactory::createField(classifier); if (field) { field->parse(); std::string result = field->evaluate(context); // 存储结果以便后续表达式引用 context.addResult(classifier.getTypeName(), result); std::cout << "表达式: \"" << field->getExpression() << "\", 类型: " << field->getTypeName() << ", 结果: " << result << std::endl; delete field; } } return 0; } ``` --- 知识点(列出该代码中遇到的知识点) | 知识点 | 描述 | |--------|------| | **表达式上下文管理** | 使用 `ExpressionContext` 管理表达式及其结果,支持表达式间的引用和计算。 | | **多态与虚函数** | 子类实现基类的虚函数接口(如 `evaluate()`),实现统一调用。 | | **字符串解析与求值** | 使用 `find`, `substr`, `istringstream` 等方法解析字符串,并在 `evaluate()` 中计算最终结果。 | --- 通过引入表达式上下文管理机制,你可以处理表达式之间的依赖关系,并确保在求值时正确引用其他表达式的结果。这使得整个解析和求值过程更加健壮和灵活。如果你有更多具体需求或问题,请继续提问 😊
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值