Skip to content

fix: avoid reentrant deadlock in DSysInfo::ensureOsVersion logging#570

Open
yixinshark wants to merge 1 commit into
linuxdeepin:masterfrom
yixinshark:fix-reentrant-log-deadlock
Open

fix: avoid reentrant deadlock in DSysInfo::ensureOsVersion logging#570
yixinshark wants to merge 1 commit into
linuxdeepin:masterfrom
yixinshark:fix-reentrant-log-deadlock

Conversation

@yixinshark

@yixinshark yixinshark commented Jul 7, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Move qWarning output out of the mutex-held region in DSysInfoPrivate::ensureOsVersion to prevent deadlock when the Qt message handler (dtklog) re-enters DSysInfo during log formatting
  • Refactor splitA_BC_DMode to accept an optional warningMessage output parameter so its diagnostic is deferred the same way
  • Move DDesktopEntry construction before the lock so its internal warnings also stay outside the critical section; replace D_ASSET_EXIT macro with explicit early returns

Context

Coordinates with a companion change in dtklog that reduces reentrancy surface in the log formatting path.

Test plan

  • Build dtk6core (Qt6) and dtkcore (Qt5)
  • Run ut_dsysinfo to verify version parsing behavior unchanged
  • Verify no qWarning is emitted while DSysInfoPrivate::mutex is held

Summary by Sourcery

Prevent reentrant deadlocks in DSysInfo OS version handling by moving warning logging and desktop entry construction outside the mutex-critical section and restructuring error handling.

Bug Fixes:

  • Avoid potential deadlock in DSysInfoPrivate::ensureOsVersion by deferring qWarning logging until after the mutex is released.

Enhancements:

  • Refactor splitA_BC_DMode and ensureOsVersion to report validation issues via an output warning message instead of immediate logging.
  • Replace macro-based early-exit checks in ensureOsVersion with structured control flow for clearer error handling.
  • Update DSysInfo copyright year range to include 2026.

@deepin-ci-robot

Copy link
Copy Markdown
Contributor

[APPROVALNOTIFIER] This PR is NOT APPROVED

This pull-request has been approved by: yixinshark

The full list of commands accepted by this bot can be found here.

Details Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

@sourcery-ai

sourcery-ai Bot commented Jul 7, 2026

Copy link
Copy Markdown

Reviewer's Guide

Refactors DSysInfoPrivate::ensureOsVersion to avoid holding the internal mutex while emitting qWarning messages by deferring construction of warning text and moving logging outside the critical section, and adjusts related helpers and callers accordingly.

Sequence diagram for updated ensureOsVersion logging without holding mutex

sequenceDiagram
    participant Client
    participant DSysInfoPrivate
    participant QMutex
    participant DDesktopEntry
    participant QtMessageHandler

    Client->>DSysInfoPrivate: ensureOsVersion()
    DSysInfoPrivate->>QMutex: QMutexLocker(mutex)
    DSysInfoPrivate->>DSysInfoPrivate: check osBuild.A and inTest()
    alt [osBuild.A > 0 and not inTest]
        QMutex-->>DSysInfoPrivate: unlocked
        DSysInfoPrivate-->>Client: return true
    else [need to read OS_VERSION_FILE]
        QMutex-->>DSysInfoPrivate: unlocked
        DSysInfoPrivate->>DDesktopEntry: DDesktopEntry(OS_VERSION_FILE)
        DSysInfoPrivate->>QMutex: QMutexLocker(mutex)
        DSysInfoPrivate->>DDesktopEntry: status()
        alt [entry.status() != DDesktopEntry::NoError]
            DSysInfoPrivate->>DSysInfoPrivate: warningMessage = "entry status: %1"
            QMutex-->>DSysInfoPrivate: unlocked
            DSysInfoPrivate->>QtMessageHandler: qWarning() << "ensureOsVersion" << warningMessage
            DSysInfoPrivate-->>Client: return false
        else [parse version]
            DSysInfoPrivate->>DSysInfoPrivate: parse OsBuild and minorVersion
            DSysInfoPrivate->>DSysInfoPrivate: splitA_BC_DMode(&warningMessage)
            QMutex-->>DSysInfoPrivate: unlocked
            alt [warningMessage not empty]
                DSysInfoPrivate->>QtMessageHandler: qWarning() << "ensureOsVersion" << warningMessage
            end
            DSysInfoPrivate-->>Client: return result
        end
    end
Loading

File-Level Changes

Change Details Files
Avoid qWarning reentrancy while holding DSysInfoPrivate::mutex in ensureOsVersion
  • Remove the always-held QMutexLocker at the top of ensureOsVersion and instead guard only the internal parsing block with a scoped lambda that locks the mutex
  • Introduce an early unlocked fast-path check for cached osBuild values both before and inside the locked lambda under !OS_VERSION_TEST_FILE
  • Construct DDesktopEntry before acquiring the mutex to avoid its internal logging from running under the DSysInfoPrivate lock
  • Replace the D_ASSET_EXIT macro with explicit validation branches that set a warning message and return false from the lambda when preconditions fail
  • Accumulate parsing/validation errors into a QString warningMessage while holding the mutex, and after unlocking, emit a single qWarning with the function name and message if present, returning the lambda result
src/dsysinfo.cpp
Make splitA_BC_DMode return deferred warning messages instead of logging directly
  • Change splitA_BC_DMode signature to accept an optional QString* warningMessage output parameter with a default of nullptr
  • Replace the direct qWarning on invalid minorVersion with logic that assigns a descriptive error message to the provided warningMessage pointer while still normalizing minVersion.D to 0
  • Update ensureOsVersion call sites to pass the shared warningMessage into splitA_BC_DMode so that A-BC-D parsing issues are reported after leaving the critical section
src/dsysinfo.cpp
Preserve version parsing behavior while clarifying control flow for different edition modes
  • Reorganize the ensureOsVersion parsing flow into a single scoped lambda that sets osBuild, majorVersion, minorVersion, and minVersion based on OsBuild.D cases (Home, community, and default A-BC-D) and returns a success flag
  • Change the Home edition (D==7) path to treat missing minorVersion as an error by setting warningMessage instead of logging directly, while preserving existing X.Y.Z parsing semantics
  • Change the community edition (D==3) path so that A.B.C and A_BC_D modes both update minVersion and its type consistently, using the new splitA_BC_DMode signature for the latter
src/dsysinfo.cpp
Minor maintenance and metadata update
  • Update SPDX-FileCopyrightText years from 2017-2023 to 2017-2026
src/dsysinfo.cpp

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@sourcery-ai sourcery-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey - I've found 1 issue

Prompt for AI Agents
Please address the comments from this code review:

## Individual Comments

### Comment 1
<location path="src/dsysinfo.cpp" line_range="253" />
<code_context>

 bool DSysInfoPrivate::ensureOsVersion()
 {
-    QMutexLocker locker(&mutex);
</code_context>
<issue_to_address>
**issue (complexity):** Consider simplifying `ensureOsVersion` by using a single mutex lock and linear control flow with one exit point for logging instead of a lambda and duplicated fast‑path logic.

You can keep the new warning behavior while simplifying `ensureOsVersion` by removing the lambda, the duplicated fast‑path, and the double locking. A single lock with a linear flow + one exit point for logging is enough.

For example:

```cpp
bool DSysInfoPrivate::ensureOsVersion()
{
    QString warningMessage;
    bool ok = true;

    QMutexLocker locker(&mutex);

#ifndef OS_VERSION_TEST_FILE // Always re-read the file when testing!
    if (osBuild.A > 0 && !inTest())
        goto end;
#endif

    DDesktopEntry entry(OS_VERSION_FILE);
    if (entry.status() != DDesktopEntry::NoError) {
        warningMessage = QStringLiteral("entry status: %1").arg(entry.status());
        ok = false;
        goto end;
    }

    // 先获取版本信息
    // ABCDE.xyz.abc
    const QString osb = entry.stringValue("OsBuild", "Version");
    const QStringList osbs = osb.split('.');

    ok = (osbs.size() >= 2 && osbs.value(0).size() == 5);
    if (!ok) {
        warningMessage = QStringLiteral("OsBuild version invalid!");
        goto end;
    }

#if QT_VERSION >= QT_VERSION_CHECK(5, 15, 0)
    const QStringList &left = osbs.value(0).split(QString(), Qt::SkipEmptyParts);
#else
    const QStringList &left = osbs.value(0).split(QString(), QString::SkipEmptyParts);
#endif
    if (left.size() != 5) {
        warningMessage = QStringLiteral("OsBuild version(ls) invalid!");
        ok = false;
        goto end;
    }

    int idx = 0;
    auto parseDigitOrAZ = [&](const QString &s, bool *outOk) -> uint {
        if (s.isEmpty()) { if (outOk) *outOk = false; return 0u; }
        const QChar ch = s.at(0);
        if (ch.isDigit()) { if (outOk) *outOk = true; return static_cast<uint>(ch.unicode() - '0'); }
        if (ch >= 'A' && ch <= 'Z') { if (outOk) *outOk = true; return static_cast<uint>(ch.toLatin1()); }
        if (outOk) *outOk = false;
        return 0u;
    };

    osBuild.A = parseDigitOrAZ(left.value(idx++, "0"), &ok);
    if (!ok) { warningMessage = QStringLiteral("OsBuild version(A) invalid!"); goto end; }
    osBuild.B = parseDigitOrAZ(left.value(idx++, "0"), &ok);
    if (!ok) { warningMessage = QStringLiteral("OsBuild version(B) invalid!"); goto end; }
    osBuild.C = parseDigitOrAZ(left.value(idx++, "0"), &ok);
    if (!ok) { warningMessage = QStringLiteral("OsBuild version(C) invalid!"); goto end; }
    osBuild.D = parseDigitOrAZ(left.value(idx++, "0"), &ok);
    if (!ok) { warningMessage = QStringLiteral("OsBuild version(D) invalid!"); goto end; }
    osBuild.E = parseDigitOrAZ(left.value(idx++, "0"), &ok);
    if (!ok) { warningMessage = QStringLiteral("OsBuild version(E) invalid!"); goto end; }

    // xyz
    osBuild.xyz = osbs.value(1).trimmed().toUInt(&ok);

    majorVersion = entry.stringValue("MajorVersion", "Version");
    minorVersion = entry.stringValue("MinorVersion", "Version");

    switch (osBuild.D) {
    case 7: {
        const QStringList &versionList = minorVersion.split('.');
        if (versionList.isEmpty()) {
            warningMessage = QStringLiteral("no minorVersion");
            ok = false;
            goto end;
        } else if (versionList.length() == 2) {
            minVersion.X = versionList.first().toUInt();
            minVersion.Y = versionList.last().toUInt();
            minVersion.Z = 0;
        } else if (versionList.length() == 3) {
            minVersion.X = versionList.at(0).toUInt();
            minVersion.Y = versionList.at(1).toUInt();
            minVersion.Z = versionList.at(2).toUInt();
        }
        minVersion.type = MinVersion::X_Y_Z;
    } break;

    case 3: {
        bool a_bc_dMode = false;
        const QStringList &versionList = minorVersion.split('.');
        if (versionList.isEmpty()) {
            warningMessage = QStringLiteral("no minorVersion");
            ok = false;
            goto end;
        } else if (versionList.length() == 1) {
            QString modeVersion = versionList.first();
            if (modeVersion.length() == 2) {
                minVersion.A = modeVersion.toUInt();
                minVersion.B = 0;
                minVersion.C = 0;
            } else {
                // A_BC_D mode
                splitA_BC_DMode(&warningMessage);
                a_bc_dMode = true;
            }
        } else if (versionList.length() == 2) {
            minVersion.A = versionList.first().toUInt();
            minVersion.B = versionList.last().toUInt();
            minVersion.C = 0;
        } else if (versionList.length() == 3) {
            minVersion.A = versionList.at(0).toUInt();
            minVersion.B = versionList.at(1).toUInt();
            minVersion.C = versionList.at(2).toUInt();
        }

        if (!a_bc_dMode)
            minVersion.type = MinVersion::A_B_C;
    } break;

    default: {
        // A-BC-D
        ok = splitA_BC_DMode(&warningMessage);
    } break;
    }

end:
    if (!warningMessage.isEmpty())
        qWarning() << "ensureOsVersion" << warningMessage;

    return ok;
}
```

This keeps:

- Single `QMutexLocker` and a single fast‑path check.
- Centralized logging via `warningMessage` at one exit point.
- All your new, more descriptive warning messages.
- Existing `splitA_BC_DMode(&warningMessage)` behavior.

But it removes:

- The inline lambda and its extra indentation / scope.
- The duplicated locking and duplicated `osBuild.A > 0 && !inTest()` check.
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

Comment thread src/dsysinfo.cpp
@@ -251,128 +252,162 @@ void DSysInfoPrivate::ensureDeepinInfo()

bool DSysInfoPrivate::ensureOsVersion()

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

issue (complexity): Consider simplifying ensureOsVersion by using a single mutex lock and linear control flow with one exit point for logging instead of a lambda and duplicated fast‑path logic.

You can keep the new warning behavior while simplifying ensureOsVersion by removing the lambda, the duplicated fast‑path, and the double locking. A single lock with a linear flow + one exit point for logging is enough.

For example:

bool DSysInfoPrivate::ensureOsVersion()
{
    QString warningMessage;
    bool ok = true;

    QMutexLocker locker(&mutex);

#ifndef OS_VERSION_TEST_FILE // Always re-read the file when testing!
    if (osBuild.A > 0 && !inTest())
        goto end;
#endif

    DDesktopEntry entry(OS_VERSION_FILE);
    if (entry.status() != DDesktopEntry::NoError) {
        warningMessage = QStringLiteral("entry status: %1").arg(entry.status());
        ok = false;
        goto end;
    }

    // 先获取版本信息
    // ABCDE.xyz.abc
    const QString osb = entry.stringValue("OsBuild", "Version");
    const QStringList osbs = osb.split('.');

    ok = (osbs.size() >= 2 && osbs.value(0).size() == 5);
    if (!ok) {
        warningMessage = QStringLiteral("OsBuild version invalid!");
        goto end;
    }

#if QT_VERSION >= QT_VERSION_CHECK(5, 15, 0)
    const QStringList &left = osbs.value(0).split(QString(), Qt::SkipEmptyParts);
#else
    const QStringList &left = osbs.value(0).split(QString(), QString::SkipEmptyParts);
#endif
    if (left.size() != 5) {
        warningMessage = QStringLiteral("OsBuild version(ls) invalid!");
        ok = false;
        goto end;
    }

    int idx = 0;
    auto parseDigitOrAZ = [&](const QString &s, bool *outOk) -> uint {
        if (s.isEmpty()) { if (outOk) *outOk = false; return 0u; }
        const QChar ch = s.at(0);
        if (ch.isDigit()) { if (outOk) *outOk = true; return static_cast<uint>(ch.unicode() - '0'); }
        if (ch >= 'A' && ch <= 'Z') { if (outOk) *outOk = true; return static_cast<uint>(ch.toLatin1()); }
        if (outOk) *outOk = false;
        return 0u;
    };

    osBuild.A = parseDigitOrAZ(left.value(idx++, "0"), &ok);
    if (!ok) { warningMessage = QStringLiteral("OsBuild version(A) invalid!"); goto end; }
    osBuild.B = parseDigitOrAZ(left.value(idx++, "0"), &ok);
    if (!ok) { warningMessage = QStringLiteral("OsBuild version(B) invalid!"); goto end; }
    osBuild.C = parseDigitOrAZ(left.value(idx++, "0"), &ok);
    if (!ok) { warningMessage = QStringLiteral("OsBuild version(C) invalid!"); goto end; }
    osBuild.D = parseDigitOrAZ(left.value(idx++, "0"), &ok);
    if (!ok) { warningMessage = QStringLiteral("OsBuild version(D) invalid!"); goto end; }
    osBuild.E = parseDigitOrAZ(left.value(idx++, "0"), &ok);
    if (!ok) { warningMessage = QStringLiteral("OsBuild version(E) invalid!"); goto end; }

    // xyz
    osBuild.xyz = osbs.value(1).trimmed().toUInt(&ok);

    majorVersion = entry.stringValue("MajorVersion", "Version");
    minorVersion = entry.stringValue("MinorVersion", "Version");

    switch (osBuild.D) {
    case 7: {
        const QStringList &versionList = minorVersion.split('.');
        if (versionList.isEmpty()) {
            warningMessage = QStringLiteral("no minorVersion");
            ok = false;
            goto end;
        } else if (versionList.length() == 2) {
            minVersion.X = versionList.first().toUInt();
            minVersion.Y = versionList.last().toUInt();
            minVersion.Z = 0;
        } else if (versionList.length() == 3) {
            minVersion.X = versionList.at(0).toUInt();
            minVersion.Y = versionList.at(1).toUInt();
            minVersion.Z = versionList.at(2).toUInt();
        }
        minVersion.type = MinVersion::X_Y_Z;
    } break;

    case 3: {
        bool a_bc_dMode = false;
        const QStringList &versionList = minorVersion.split('.');
        if (versionList.isEmpty()) {
            warningMessage = QStringLiteral("no minorVersion");
            ok = false;
            goto end;
        } else if (versionList.length() == 1) {
            QString modeVersion = versionList.first();
            if (modeVersion.length() == 2) {
                minVersion.A = modeVersion.toUInt();
                minVersion.B = 0;
                minVersion.C = 0;
            } else {
                // A_BC_D mode
                splitA_BC_DMode(&warningMessage);
                a_bc_dMode = true;
            }
        } else if (versionList.length() == 2) {
            minVersion.A = versionList.first().toUInt();
            minVersion.B = versionList.last().toUInt();
            minVersion.C = 0;
        } else if (versionList.length() == 3) {
            minVersion.A = versionList.at(0).toUInt();
            minVersion.B = versionList.at(1).toUInt();
            minVersion.C = versionList.at(2).toUInt();
        }

        if (!a_bc_dMode)
            minVersion.type = MinVersion::A_B_C;
    } break;

    default: {
        // A-BC-D
        ok = splitA_BC_DMode(&warningMessage);
    } break;
    }

end:
    if (!warningMessage.isEmpty())
        qWarning() << "ensureOsVersion" << warningMessage;

    return ok;
}

This keeps:

  • Single QMutexLocker and a single fast‑path check.
  • Centralized logging via warningMessage at one exit point.
  • All your new, more descriptive warning messages.
  • Existing splitA_BC_DMode(&warningMessage) behavior.

But it removes:

  • The inline lambda and its extra indentation / scope.
  • The duplicated locking and duplicated osBuild.A > 0 && !inTest() check.

@yixinshark yixinshark force-pushed the fix-reentrant-log-deadlock branch from 38bd83b to 6205648 Compare July 7, 2026 05:45
Move qWarning output out of the mutex-held region in
DSysInfoPrivate::ensureOsVersion. Previously, qWarning was called
while holding DSysInfoPrivate::mutex, which can deadlock if the
installed Qt message handler (dtklog) re-enters DSysInfo during
log formatting. Now warning text is collected into a local
QString and emitted after the lock is released.

Also refactor splitA_BC_DMode to accept an optional warningMessage
output parameter so its diagnostic is deferred the same way, and
replace the D_ASSET_EXIT macro with explicit early returns for
clarity. The DDesktopEntry construction is moved before the lock
so its internal warnings also stay outside the critical section.

修复 DSysInfo::ensureOsVersion 中持锁日志导致的重入死锁

将 qWarning 输出从 DSysInfoPrivate::ensureOsVersion 持锁区域移到
锁释放之后。此前在持有 DSysInfoPrivate::mutex 时调用 qWarning,若
已安装的 Qt 消息处理器(dtklog)在日志格式化过程中再次进入
DSysInfo,会导致死锁。现在告警信息先收集到局部 QString,在释放
锁后再输出。

同时重构 splitA_BC_DMode 增加可选的 warningMessage 输出参数,使
其诊断信息同样延迟输出;用显式提前返回替代 D_ASSET_EXIT 宏以
提升可读性。DDesktopEntry 构造移到加锁之前,使其内部告警也保持
在临界区之外。

Log: fix reentrant deadlock in DSysInfo::ensureOsVersion logging
Change-Id: I031975ecf72528d1c2f3e48bd546e7d710641df5
@yixinshark yixinshark force-pushed the fix-reentrant-log-deadlock branch from 6205648 to 39fa460 Compare July 7, 2026 06:21
@deepin-ci-robot

Copy link
Copy Markdown
Contributor

deepin pr auto review

★ 总体评分:95分

■ 【总体评价】

代码成功重构了多线程下的版本解析逻辑,彻底解决了数据竞争与脏状态问题
逻辑基本正确且性能高效,仅因布尔标志位未使用原子类型存在极低概率的理论竞态扣5分

■ 【详细分析】

  • 1.语法逻辑(基本正确)✓

代码将原本在互斥锁内直接修改成员变量并通过宏提前返回的逻辑,重构为在无锁状态下解析到局部变量、最后加锁一次性赋值的模式,彻底消除了因解析中途失败导致成员变量处于“半解析”脏状态的问题。splitA_BC_DMode 函数改为参数化传递,隔离性良好。
潜在问题:osVersionParsed 被声明为普通 bool,在 ensureOsVersion 开头进行了无锁读取判断。在 C++ 内存模型中,如果一个线程在写该变量而另一个线程在读,即使变量是单字节的 bool,严格意义上也属于数据竞争,在弱内存模型架构上可能导致读取到过期值。
建议:将 bool osVersionParsed 修改为 std::atomic<bool> osVersionParsed,以确保跨线程的可见性与原子性。

  • 2.代码质量(良好)✓

移除了具有隐藏控制流副作用的 D_ASSET_EXIT 宏,使用局部的 ok 标志位和 warningMessage 字符串收集错误,最后统一进行日志输出,大幅提升了代码的可读性和可维护性。OSBuild 结构体增加了 E(0) 的初始化,消除了未初始化隐患。
潜在问题:无
建议:无

  • 3.代码性能(高效)✓

将耗时的文件读取与字符串解析操作移出互斥锁保护区域,仅在最后提交解析结果时持有锁,极大缩短了临界区长度,有效降低了多线程并发调用时的锁竞争阻塞。
潜在问题:无
建议:无

  • 4.代码安全(存在0个安全漏洞)✓

漏洞对比统计:新增漏洞 0 个,减少漏洞 1 个,持平 0 个
原代码在持有锁期间直接修改成员变量,若解析失败触发宏提前返回,会导致其他线程读取到被部分修改的脏数据,属于数据竞争漏洞。本次重构通过局部变量中转彻底消除了此漏洞。AI独立分析未发现命令注入、越界、泄露等新的安全漏洞。

  • 建议:继续保持这种无锁解析、加锁提交的线程安全设计模式

■ 【改进建议代码示例】

--- a/src/dsysinfo.cpp
+++ b/src/dsysinfo.cpp
@@ -91,7 +91,7 @@ class Q_DECL_HIDDEN DSysInfoPrivate
     };
 
     MinVersion minVersion;
     OSBuild osBuild;
-    bool osVersionParsed = false;
+    std::atomic<bool> osVersionParsed{false};
     bool splitA_BC_DMode(const QString &minorVersion, MinVersion *minVersion, QString *warningMessage = nullptr);
 #endif

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants