You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

多线程应用中GetProcessMemoryInfo及MemoryTester代码是否线程安全?

多线程环境下这段代码的线程安全性分析

结论:这段代码并非线程安全,核心问题集中在静态成员变量s_memoryLimitInBytes的读写同步机制缺失上,具体问题如下:

1. 共享变量的读写存在原子性与可见性风险

静态变量s_memoryLimitInBytes被多线程共享,setMemoryLimitInBytes是写入操作,checkIfMemoryExceedsLimit、getMemoryLimitInBytes是读取操作:

  • 虽然size_t的单次读写在x86/x64等平台可能表现为原子操作,但C++标准不保证其原子性,在弱内存模型的平台上可能出现部分写入的异常情况。
  • 更关键的是可见性问题:一个线程修改变量后,其他线程可能因CPU缓存机制,无法立即读取到最新值,导致基于过期数据的错误判断。

2. 复合操作存在竞态条件

checkIfMemoryExceedsLimit函数包含两次对s_memoryLimitInBytes的读取:

if (s_memoryLimitInBytes == 0) { // 第一次读取
    return false;
}
return (getMemoryUseInBytes() > s_memoryLimitInBytes); // 第二次读取

两次读取之间,若有其他线程调用setMemoryLimitInBytes修改变量值,会直接破坏逻辑正确性:

  • 比如线程A第一次读取到变量为0,准备返回false时,线程B将其设置为非0值,此时线程A本该执行内存检查却直接返回,失去了内存限制的作用。
  • 反之,若第一次读取到非0值,但第二次读取前变量被改为0,会出现用内存使用量和0比较的错误判断。

3. 可安全使用的部分

getMemoryUseInBytes调用的Windows API(GetCurrentProcess、GetProcessMemoryInfo)本身是线程安全的,系统级API内部已处理多线程访问的同步逻辑,这部分不会引发线程安全问题。

修复建议

要实现线程安全,可通过两种方式处理:

  • 使用C++标准库的std::atomic<size_t>替换普通size_t,原子类型可保证读写的原子性与可见性。
  • 若需保证checkIfMemoryExceedsLimit这类复合操作的原子性,需添加互斥锁(如std::mutex),确保整个判断过程不被其他线程的写入操作打断。

原子类型修改示例

MemoryTester.h

#include <atomic>

class MemoryTester
{
public:
    static bool checkIfMemoryExceedsLimit();
    static void setMemoryLimitInBytes(size_t limit);
    static size_t getMemoryLimitInBytes();
    static size_t getMemoryUseInBytes();

private:
    static std::atomic<size_t> s_memoryLimitInBytes;
};

MemoryTester.cpp

#include "MemoryTester.h"
#include "windows.h"
#include "psapi.h"

std::atomic<size_t> MemoryTester::s_memoryLimitInBytes = 0;

bool MemoryTester::checkIfMemoryExceedsLimit()
{
    size_t limit = s_memoryLimitInBytes.load(std::memory_order_acquire);
    if (limit == 0)
    {
        return false;
    }
    return (getMemoryUseInBytes() > limit);
}

void MemoryTester::setMemoryLimitInBytes(size_t limit)
{
    s_memoryLimitInBytes.store(limit, std::memory_order_release);
}

size_t MemoryTester::getMemoryLimitInBytes()
{
    return s_memoryLimitInBytes.load(std::memory_order_acquire);
}

size_t MemoryTester::getMemoryUseInBytes()
{
    PROCESS_MEMORY_COUNTERS_EX pmc;
    GetProcessMemoryInfo(GetCurrentProcess(), (PROCESS_MEMORY_COUNTERS*)&pmc, sizeof(pmc));
    return pmc.PrivateUsage;
}

内容的提问来源于stack exchange,提问作者SIMEL

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.07 03:44:53