windows線程同步-原子操作-Interlocked系列函數(用戶模式)


Interlocked系列函數用來保證原子訪問。
InterlockedExchangeAdd提供保證long類型的原子操作。
InterlockedExchangeAdd64提供long long 64位的原子操作。
搞不懂為什么不提供int類型的,int類型轉換成long類型就是2個不同內存地址的變量,
再來對long類型進行原子操作也就沒用了?
(這里請教了下c++網友,說是vs2010對類型檢查很嚴格,可能之前的編譯器也許會放松點?)
int類型要進行原子操作只能強轉為long指針了
static int l=0;
unsigned __stdcall ThreadFun(void* par)
{
//注意這里的強轉,不會改變內存地址導致原子操作無效
InterlockedExchangeAdd((long*)&l,1);
return 0;
}

#include <iostream>
#include <process.h>
#include <windows.h>
using namespace std;

static long l=0;
unsigned __stdcall ThreadFun(void* par)
{ 
   InterlockedExchangeAdd(&l,1);
   return 0;
}

int main()
{
    HANDLE hThread[2];
    hThread[0]=(HANDLE)_beginthreadex(NULL,0,&ThreadFun,NULL,0,NULL);
    hThread[1]=(HANDLE)_beginthreadex(NULL,0,&ThreadFun,NULL,0,NULL);
    //等待所有線程結束
    WaitForMultipleObjects(2,hThread,true,INFINITE);
    CloseHandle(hThread[0]);
    CloseHandle(hThread[1]);
    //就算沒有進行原子操作,測試的時候基本上還是輸出2,極少輸出1,變量++是秒殺完成的。
    //在實際項目的大並發情況下那么結果是1就很容易出現
    cout<<"l="<<l<<endl;
    system("PAUSE");
    return 0;
}

上面幾個函數返回由加數指向的變量的初始值,
long i=0;
cout<<InterlockedExchangeAdd(&i,1)<<endl;//輸出0
cout<<InterlockedExchangeAdd(&i,1)<<endl;//輸出1

書上提到Interlocked速度很快,這點不錯,C#中經常用相應的函數,而且不需要在用戶模型和內核模式之前切換
另外提到的一個重要點,原子操作的變量必須是內存對齊的。

 

上面的是對變量進行原子增加,下面的幾個函數是講參數變為指定的值(原子操作)。
InterlockedExchange
InterlockedExchange64
InterlockedExchangePointer//如果應用程序是32位,那么這里替換的就是32位,64位程序則對應

用InterlockedExchange實現旋轉鎖

#include <iostream>
#include <process.h>
#include <windows.h>
using namespace std;

BOOL b=FALSE;
unsigned __stdcall ThreadFun(void* par)
{
    int* pout=(int*)par;
    while(InterlockedExchange((unsigned long*)&b,TRUE)==TRUE)
    {
        Sleep(500);
    }
    for(int i=0;i<3;i++)
    {
        Sleep(1000);
         cout<<*pout<<endl;
    }
    InterlockedExchange((unsigned long*)&b,FALSE);
    return 0;
}
int main()
{
    HANDLE hThread[2];
    int a1=1;
    int a2=2;
    hThread[0]=(HANDLE)_beginthreadex(NULL,0,&ThreadFun,&a1,0,NULL);
    hThread[1]=(HANDLE)_beginthreadex(NULL,0,&ThreadFun,&a2,0,NULL);
    //等待所有線程結束
    WaitForMultipleObjects(2,hThread,true,INFINITE);
    CloseHandle(hThread[0]);
    CloseHandle(hThread[1]);
    system("PAUSE");
    return 0;
}

windows核心編程提到,旋轉鎖很費cpu,這里把Sleep時間設置長點就不浪費了吧,但是卻不能及時搶到資源所有權。
旋轉鎖貌似就是實現了對代碼塊的鎖定,假如我們沒有使用c#中lock等鎖定代碼塊的,或者也沒用底層的CRITICAL_SECTION,那么要鎖定代碼塊貌似我知道的就旋轉鎖。

Interlocked系列函數還剩下下面2個,功能是以原子操作方式進行對比和設置。具體查詢msdn。
InterlockedCompareExchange
InterlockedCompareExchangePointer

本文版權歸kennyMc和博客園共有,歡迎轉載,但未經作者同意必須保留此段聲明,且在文章頁面明顯位置給出原文連接,否則保留追究法律責任的權利。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM