承接网站建设,wordpress主题自定义,wordpress数据库忘记了,爱给网素材官网线程
常见问题
同步权限
在多线程 / 多进程并发时#xff0c;为避免共享资源#xff08;如内存变量、硬件设备、文件#xff09;被同时修改导致的数据不一致#xff0c;需要通过 “同步机制” 控制谁能访问资源 ——“获取同步权限” 就是线程 / 进程申请这种访问资格的过程…线程
常见问题
同步权限
在多线程 / 多进程并发时为避免共享资源如内存变量、硬件设备、文件被同时修改导致的数据不一致需要通过 “同步机制” 控制谁能访问资源 ——“获取同步权限” 就是线程 / 进程申请这种访问资格的过程。
v4 _InterlockedCompareExchange(a1, 1, 0);第一个参数 a1指向目标内存地址的指针通常是一个共享变量如 LONG* 类型即要操作的 “共享资源标记”。第二个参数 1当比较成功时要写入目标内存地址的 “新值”。第三个参数 0“预期值”即我们认为目标内存当前应该有的值。返回值是操作前目标内存地址a1 指向的地址中的原始值
// 定义一个共享的“锁标记”0表示未占用1表示已占用
LONG lock_flag 0;// 线程A尝试获取锁
LONG original _InterlockedCompareExchange(lock_flag, 1, 0);
if (original 0) {//获取到权限// 执行临界区操作...// 操作完成后释放锁如将lock_flag设回0
} else {// 获取锁失败锁已被其他线程占用// 可选择等待、重试或放弃
}临界区
临界区Critical Section 指的是一段 “不能被多个线程同时执行” 的代码片段当一个线程正在执行临界区代码时其他线程必须等待该线程执行完毕才能进入同一临界区。
原子性
“原子”Atomic描述的是一个不可分割、不可中断的操作单元。一个 “原子操作” 要么完整地执行完毕要么完全不执行中间不会被任何其他线程、进程或中断打断不存在 “执行到一半” 的中间状态。
假设两个线程Thread A、Thread B同时对共享变量 count初始值为 0执行 count 1 操作。
在底层会拆分为 3 个 CPU 指令
从内存读取 count 的值到 CPU 寄存器如 mov eax, [count]寄存器中的值加 1如 inc eax将寄存器的值写回内存如 mov [count], eax。
如果操作不原子可能出现以下 “交错执行”
Thread A 执行步骤 1读取 count0 到寄存器此时 CPU 切换到 Thread BThread B 执行步骤 1-3读取 count0 → 加 1→ 写回 count1CPU 切回 Thread A继续执行步骤 2-3寄存器值加 10→1→ 写回 count1
最终 count 的结果是 1但预期是 2。
原子操作的本质
“原子性” 需要硬件CPU提供底层支持再配合软件操作系统、编程语言库封装成易用的接口。
硬件层CPU 的原子指令支持
不同架构的 CPU 会提供专门的 “原子操作指令”确保单个指令的不可分割性
x86/x86_64 架构通过 lock 前缀实现原子性如 lock cmpxchg、lock inc。lock 前缀会让 CPU 在执行指令期间 “锁定系统总线”阻止其他 CPU 核心同时访问该内存地址确保指令执行不被打断ARM 架构提供 ldrex原子加载、strex原子存储等指令通过 “独占访问内存” 机制实现原子性RISC-V 架构通过 amoswap.w、amoadd.w 等 “原子内存操作指令”AMO 指令实现原子性。
这些硬件指令是 “原子操作” 的基石 —— 软件层面的原子接口如 C 的 std::atomic、Windows 的 _InterlockedXXX本质都是对这些 CPU 指令的封装。
软件层原子操作的封装与扩展
硬件指令通常只支持 “单个内存地址的简单操作”如加 1、比较交换软件会在此基础上封装更灵活的原子操作
原子操作
原子的交换操作
_InterlockedExchange(state_lock, 2);第一个参数 state_lock指向目标内存地址的指针通常是一个共享变量如 LONG* 类型即要被修改的 “状态标记”。第二个参数 2要写入目标内存地址的 “新值”。返回值原子地将 state_lock 指向的内存值更新为 2同时返回该内存地址在更新前的原始值
原子比较交换操作
_InterlockedCompareExchange(lock_flag, 1, 0);参数1类型为 volatile LONG*指向 32 位有符号整数的指针要操作的目标内存地址
参数2类型为 LONG32 位有符号整数比较成功后要写入目标地址的值
参数3类型为 LONG表示预期的目标地址当前值即 “旧值”。
返回值返回值为 LONG 类型即目标地址在操作执行前的原始值
// 定义一个共享的“锁标记”0表示未占用1表示已占用
LONG lock_flag 0;// 线程A尝试获取锁
LONG original _InterlockedCompareExchange(lock_flag, 1, 0);
if (original 0) {//获取到权限// 执行临界区操作...// 操作完成后释放锁如将lock_flag设回0
} else {// 获取锁失败锁已被其他线程占用// 可选择等待、重试或放弃
}原子地将目标变量的值加
_InterlockedIncrement(dword_14002BFF0);参数dword_14002BFF0 是一个 LONG 类型32 位的共享变量通常是全局或多线程可见的变量表示要进行递增操作的目标。
返回值函数返回递增后的新值LONG 类型。
原子减 1
_InterlockedDecrement(a1)参数:类型为 volatile LONG*指向 32 位有符号整数的指针
返回值类型为 LONG32 位有符号整数表示减 1 操作完成后的结果值即 *a1 - 1 的结果。
线程同步
SRW 锁
SRW 锁支持两种获取模式
共享模式Shared Mode多个线程可同时获取适用于 “只读操作” 场景多个读者可并行访问资源。独占模式Exclusive Mode仅允许一个线程获取适用于 “修改操作” 场景写者需独占资源。
初始化SRW
void InitializeSRWLock(PSRWLOCK SRWLock
);参数PSRWLOCK 是 SRWLOCK* 的类型别名指向 SRWLOCK 结构体轻量级读写锁的核心数据结构。
核心作用初始化 SRW 锁对象的内部状态初始化后的 SRW 锁可通过以下函数实现读写分离的同步
读操作AcquireSRWLockShared获取共享锁和 ReleaseSRWLockShared释放共享锁。写操作AcquireSRWLockExclusive获取独占锁和 ReleaseSRWLockExclusive释放独占锁。
读操作
void AcquireSRWLockShared(PSRWLOCK SRWLock
);参数 SRWLock 是指向 SRWLOCK 结构体的指针,让线程以 “共享模式”只读模式安全地获取轻量级读写锁SRW Lock。
void ReleaseSRWLockShared(PSRWLOCK SRWLock
);参数 SRWLock 是指向 SRWLOCK 结构体的指针PSRWLOCK 即 SRWLOCK*表示要释放的轻量级读写锁对象。
写操作
void AcquireSRWLockExclusive(PSRWLOCK SRWLock
);让线程以 “独占模式” 获取 SRW 锁确保对共享资源的修改操作写操作具有原子性
临界区
进出临界区
EnterCriticalSection(stru_14002C030)参数类型为LPCRITICAL_SECTION即 CRITICAL_SECTION*指向临界区结构体的指针。
无返回值
作用让当前线程 “获取临界区的访问权”
LeaveCriticalSection(stru_14002C030);作用释放临界区
初始化临界区
void InitializeCriticalSection(LPCRITICAL_SECTION lpCriticalSection
);参数 lpCriticalSection 是指向 CRITICAL_SECTION 结构体的指针LPCRITICAL_SECTION 是 CRITICAL_SECTION* 的类型别名表示要初始化的临界区对象。
异常如果初始化失败通常是由于系统资源不足函数会触发一个异常而非返回错误码。因此在实际使用中可能需要配合异常处理如 __try/__except捕获潜在错误。
作用初始化临界区对象的内部状态初始化后的临界区可通过 EnterCriticalSection进入临界区和 LeaveCriticalSection离开临界区实现。
使用示例
// 定义临界区对象全局或栈上
CRITICAL_SECTION CriticalSection;// 初始化临界区通常在程序启动或模块初始化时调用
InitializeCriticalSection(CriticalSection);// 多线程场景中使用
void ThreadFunc() {// 进入临界区获取同步权限EnterCriticalSection(CriticalSection);// 执行需要同步的操作如访问共享资源AccessSharedResource();// 离开临界区释放同步权限LeaveCriticalSection(CriticalSection);
}// 程序退出前销毁临界区释放资源
DeleteCriticalSection(CriticalSection);临界区同步
TryEnterCriticalSection()参数LPCRITICAL_SECTION lpCriticalSection指向 CRITICAL_SECTION 结构体的指针与 EnterCriticalSection 相同,表示要尝试进入的临界区对象需提前通过 InitializeCriticalSection 初始化。
返回值: TRUE非 0 值表示成功进入临界区,FALSE0表示未能进入临界区。
作用非阻塞尝试进入临界区与 EnterCriticalSection 的 “阻塞等待” 不同TryEnterCriticalSection 的核心特点是 “尝试进入失败立即返回”适用于以下场景
当线程只需 “短暂尝试” 获取临界区若失败则执行其他任务而非等待避免线程阻塞。实现 “超时等待” 逻辑结合循环和 Sleep多次尝试后放弃。
临界区状态结构体
00000000 struct _RTL_CRITICAL_SECTION // sizeof0x28
00000000 { // XREF: .data:CriticalSection/r
00000000 // .data:__rtl_critical_section/r
00000000 PRTL_CRITICAL_SECTION_DEBUG DebugInfo;
00000008 LONG LockCount;
0000000C LONG RecursionCount;
00000010 HANDLE OwningThread;
00000018 HANDLE LockSemaphore;
00000020 ULONG_PTR SpinCount;
00000028 };线程调度
CPU 时间片
SwitchToThread() 返回值
返回 TRUE非 0 值表示当前有其他 “就绪状态” 的线程属于同一优先级或更高优先级被调度执行返回 FALSE0表示当前没有其他就绪线程可调度即系统中只有当前线程可运行。
作用
当前线程主动放弃剩余的 CPU 时间片让操作系统调度器重新选择一个就绪线程通常是同优先级的其他线程运行。
自旋等待
while ( 1 )
{v6 _InterlockedCompareExchange(a1, 1, 0); // 原子比较交换尝试将a1从0改为1if ( !v6 ) // v60表示成功获取权限a1原本为0已改为1break;if ( v6 ! 2 ) // 若a1当前为1被其他线程占用则主动让出CPUSwitchToThread();if ( *a1 2 ) // 若等待期间a1变为2终止则返回0return 0LL;
}