读书笔记:Windows核心编程第八章---用户方式中的线程同步技巧
2013-04-14 12:40
363 查看
Windows核心编程第八章 用户方式中的线程同步技巧
线程在以下两种情况下需要互相通信:
1、当有多个线程访问共享资源而不使资源被破坏的时候;
2、当一个线程需要将某个任务完成的情况通知另一个或多个线程时候。
一、原子访问:互锁的函数家族
原子访问是指线程在访问资源时候能够确保所有的其他线程都不在同一时间内访问相同的资源。
以下函数会把第二个参数的值以原子操作的方式加到第一个参数指向的指上:
LONG InterlockedExchangeAdd(
PLONG plAdded,
LONG Increment);
LONGLONG InterlockedExchangeAdd64(
PLONG plAdded,
LONG Increment);
他执行的极快一般只需要小于50个CPU周期;也不需要在用户模式和内核模式中切换(这个一般需要1000个以上的CPU周期)。
以下三个函数会把第一个参数指向的内存地址替换为第二个参数指定的值:
LONG InterlockedExchange(
PLONG volatile plTarget,
LONG lvalue);
LONGLONG InterlockedExchange64(
PLONGLONG volatile plTarget,
LONGLONG lvalue);
PVOID InterlockedExchangePointer(
PVOID* volatile pplTarget,
PVOID pvlvalue);
这个函数可以用于实现循环锁,循环锁在循环的时候会浪费CPU时间,我们可以使用Sleep()或者使用SwitchRiThread(),同时我们必须确保循环锁变量和锁保护的数据位于不同的高速缓存行,一面使用资源的CPU和任何试图访问资源的CPU发生争夺,影响性能。。。
下面是最后两个InterLocked交换函数,他们将参数一和参数三进行比较如果参数一等于参数三那么就吧参数而赋值给参数一:
PLONG InterlockedCompareExchange(
PLONG plDestination,
LONG lExchange,
LONG lComparand);
PLONG InterlockedCompareExchange(
PVOID* ppvlDestination,
PVOID pvlExchange,
PVOID pvlComparand);
二、高速缓存行
当CPU从内存里读取一个字节的时候,他并不是从内存中取回一个字节,而是取回一个高速缓存行,当一个CPU改变自己的高速缓存行的时候他会通知其他的CPU使自己的高速缓存行作废。。。所以我们必须根据缓存行的大小将应用程序的数据组织到一起,并且将数据缓存行边界对齐。遮掩做的目的是为了确保不同的CPU能够各自访问不同的内存地址,而且这些地址不在一个高速缓存行中。
我们使用GetLogicalProcessorInformation函数,他会返回一个SYSTEM_LOGICAL_PROCESSOR_INFORMATION结构,检查其中的Cache字段里面的LineSize字段表示高速缓存行大小。遮掩我们就可以使用C/C++编译器的__declspec(align(#))来对字段对齐加以控制。。。
三、高级线程同步
通用的规则,我不既不应该使用旋转锁也不应该进行轮询,而应该调用函数把线程切换到等待状态,知道县城想要访问的资源可供使用为止。。。使用volatile关键字防止编译器对代码做某些不必要的优化。。。。
四、关键段
关键段函数:
VOID InitializeCriticalSection(PCRITICAL_SECTION pcs);
VOID DeleteCriticalSection(PCRITICAL_SECTION pcs);
VOID EnterCriticalSection(PCRITICAL_SECTION pcs);
VOID LeaveCriticalSection(PCRITICAL_SECTION pcs);
BOOL TryEnterCriticalSection(PCRITICAL_SECTION pcs);
关键段和旋转锁一起使用:
BOOL InitializeCriticalSectionAndSpinCount(
PCRITICAL_SECTION pcs,
DWORD dwSpinCount);
DWORD SetCriticalSectionSpinCount(
PCRITICAL_SECTION pcs,
DWORD dwSpinCount);
关键段的错误处理,处理结构化异常。。。
五、Slim读写锁
SRWLock他目的和关键段相同,但是他区分读取线程和写入线程、读取线程共享操作、写入线程独占操作:
VOID InitializeSRWLock(PSRWLOCK SRWLock);
VOID AcquireSRWLockExclusive(PSRWLOCK SRWLock);
VOID ReleaseSRWLockExclusive(PSRWLOCK SRWLock);
VOID AcquireSRWLockShare(PSRWLOCK SRWLock);
VOID ReleaseSRWLockShare(PSRWLOCK SRWLock);
六、条件变量
有时候我们想让线程以原子方式把锁释放并将自己阻塞,知道某个条件成立为止:
BOOL SleepConditionVariablecs(
PCONDITION_VARIABLE pConditionSection,
PCRITICAL_SECTION pCriticalSection,
DWOED dwMilliseconds);
BOOL SleepConditionVariableSRW(
PCONDITION_VARIABLE pConditionSection,
PSRWLOCK pSRWLOCK,
DWOED dwMilliseconds,
ULONG Flags);
BOOL WakeConditionVariable(
PCONDITION_VARIABLE pConditionSection);
BOOL WakeAllConditionVariable(
PCONDITION_VARIABLE pConditionSection);
七、一些有用的窍门和技巧
1、以原子方式操作一组对象时使用一个锁;
2、同时访问多个逻辑资源使用的锁的次序相同;
3、不要长时间使用锁;
线程在以下两种情况下需要互相通信:
1、当有多个线程访问共享资源而不使资源被破坏的时候;
2、当一个线程需要将某个任务完成的情况通知另一个或多个线程时候。
一、原子访问:互锁的函数家族
原子访问是指线程在访问资源时候能够确保所有的其他线程都不在同一时间内访问相同的资源。
以下函数会把第二个参数的值以原子操作的方式加到第一个参数指向的指上:
LONG InterlockedExchangeAdd(
PLONG plAdded,
LONG Increment);
LONGLONG InterlockedExchangeAdd64(
PLONG plAdded,
LONG Increment);
他执行的极快一般只需要小于50个CPU周期;也不需要在用户模式和内核模式中切换(这个一般需要1000个以上的CPU周期)。
以下三个函数会把第一个参数指向的内存地址替换为第二个参数指定的值:
LONG InterlockedExchange(
PLONG volatile plTarget,
LONG lvalue);
LONGLONG InterlockedExchange64(
PLONGLONG volatile plTarget,
LONGLONG lvalue);
PVOID InterlockedExchangePointer(
PVOID* volatile pplTarget,
PVOID pvlvalue);
这个函数可以用于实现循环锁,循环锁在循环的时候会浪费CPU时间,我们可以使用Sleep()或者使用SwitchRiThread(),同时我们必须确保循环锁变量和锁保护的数据位于不同的高速缓存行,一面使用资源的CPU和任何试图访问资源的CPU发生争夺,影响性能。。。
下面是最后两个InterLocked交换函数,他们将参数一和参数三进行比较如果参数一等于参数三那么就吧参数而赋值给参数一:
PLONG InterlockedCompareExchange(
PLONG plDestination,
LONG lExchange,
LONG lComparand);
PLONG InterlockedCompareExchange(
PVOID* ppvlDestination,
PVOID pvlExchange,
PVOID pvlComparand);
二、高速缓存行
当CPU从内存里读取一个字节的时候,他并不是从内存中取回一个字节,而是取回一个高速缓存行,当一个CPU改变自己的高速缓存行的时候他会通知其他的CPU使自己的高速缓存行作废。。。所以我们必须根据缓存行的大小将应用程序的数据组织到一起,并且将数据缓存行边界对齐。遮掩做的目的是为了确保不同的CPU能够各自访问不同的内存地址,而且这些地址不在一个高速缓存行中。
我们使用GetLogicalProcessorInformation函数,他会返回一个SYSTEM_LOGICAL_PROCESSOR_INFORMATION结构,检查其中的Cache字段里面的LineSize字段表示高速缓存行大小。遮掩我们就可以使用C/C++编译器的__declspec(align(#))来对字段对齐加以控制。。。
三、高级线程同步
通用的规则,我不既不应该使用旋转锁也不应该进行轮询,而应该调用函数把线程切换到等待状态,知道县城想要访问的资源可供使用为止。。。使用volatile关键字防止编译器对代码做某些不必要的优化。。。。
四、关键段
关键段函数:
VOID InitializeCriticalSection(PCRITICAL_SECTION pcs);
VOID DeleteCriticalSection(PCRITICAL_SECTION pcs);
VOID EnterCriticalSection(PCRITICAL_SECTION pcs);
VOID LeaveCriticalSection(PCRITICAL_SECTION pcs);
BOOL TryEnterCriticalSection(PCRITICAL_SECTION pcs);
关键段和旋转锁一起使用:
BOOL InitializeCriticalSectionAndSpinCount(
PCRITICAL_SECTION pcs,
DWORD dwSpinCount);
DWORD SetCriticalSectionSpinCount(
PCRITICAL_SECTION pcs,
DWORD dwSpinCount);
关键段的错误处理,处理结构化异常。。。
五、Slim读写锁
SRWLock他目的和关键段相同,但是他区分读取线程和写入线程、读取线程共享操作、写入线程独占操作:
VOID InitializeSRWLock(PSRWLOCK SRWLock);
VOID AcquireSRWLockExclusive(PSRWLOCK SRWLock);
VOID ReleaseSRWLockExclusive(PSRWLOCK SRWLock);
VOID AcquireSRWLockShare(PSRWLOCK SRWLock);
VOID ReleaseSRWLockShare(PSRWLOCK SRWLock);
六、条件变量
有时候我们想让线程以原子方式把锁释放并将自己阻塞,知道某个条件成立为止:
BOOL SleepConditionVariablecs(
PCONDITION_VARIABLE pConditionSection,
PCRITICAL_SECTION pCriticalSection,
DWOED dwMilliseconds);
BOOL SleepConditionVariableSRW(
PCONDITION_VARIABLE pConditionSection,
PSRWLOCK pSRWLOCK,
DWOED dwMilliseconds,
ULONG Flags);
BOOL WakeConditionVariable(
PCONDITION_VARIABLE pConditionSection);
BOOL WakeAllConditionVariable(
PCONDITION_VARIABLE pConditionSection);
七、一些有用的窍门和技巧
1、以原子方式操作一组对象时使用一个锁;
2、同时访问多个逻辑资源使用的锁的次序相同;
3、不要长时间使用锁;
相关文章推荐
- Windows核心编程 第八章 用户方式中线程的同步(上)
- 【windows核心编程】 第八章 用户模式下的线程同步
- Windows核心编程 第八章 用户方式中线程的同步(下)
- windows核心编程之用户方式中的线程同步
- 【windows核心编程】 第八章 用户模式下的线程同步
- 复习笔记之二--用户方式线程同步
- 用户方式中线程同步
- Windows核心编程:(五)用户模式下线程同步
- 用户方式中线程的同步——Windows核心编程学习手札之八
- CLR via C# 读书笔记 4-1 线程同步-常见的锁,原生用户模式和核心模式 (上)
- Windows应用程序启动方式---------《windows核心编程》读书笔记(2)
- Windows核心编程(七)用户模式下的线程同步
- Windows核心编程——第8章 用户模式下的线程同步
- 《Windows核心编程5》第八章-用户模式下的线程同步
- windows核心编程---用户模式下的线程同步
- Windows Via C/C++ 读书笔记 5 用户模式的线程同步
- C8、 用户方式的线程同步
- 《Windows核心编程》读书笔记九 用内核模式进行线程同步
- 《Windows核心编程 5th》读书笔记---第8章 用户模式下的线程同步
- 《Windows核心编程 5th》读书笔记----第9章 用内核对象进行线程同步