• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            信號量

              信號量是維護0到指定最大值之間的同步對象。信號量狀態(tài)在其計數(shù)大于0時是有信號的,而其計數(shù)是0時是無信號的。信號量對象在控制上可以支持有限數(shù)量共享資源的訪問。

              信號量的特點和用途可用下列幾句話定義:

             ?。?)如果當前資源的數(shù)量大于0,則信號量有效;

             ?。?)如果當前資源數(shù)量是0,則信號量無效;

             ?。?)系統(tǒng)決不允許當前資源的數(shù)量為負值;

             ?。?)當前資源數(shù)量決不能大于最大資源數(shù)量。

              創(chuàng)建信號量

            HANDLE CreateSemaphore (
             PSECURITY_ATTRIBUTE psa,
             LONG lInitialCount, //開始時可供使用的資源數(shù)
             LONG lMaximumCount, //最大資源數(shù)
            PCTSTR pszName);

              釋放信號量

              通過調用ReleaseSemaphore函數(shù),線程就能夠對信標的當前資源數(shù)量進行遞增,該函數(shù)原型為:

            BOOL WINAPI ReleaseSemaphore(
             HANDLE hSemaphore,
             LONG lReleaseCount, //信號量的當前資源數(shù)增加lReleaseCount
             LPLONG lpPreviousCount
            );

              打開信號量

              和其他核心對象一樣,信號量也可以通過名字跨進程訪問,打開信號量的API為:

            HANDLE OpenSemaphore (
             DWORD fdwAccess,
             BOOL bInherithandle,
             PCTSTR pszName
            );

              互鎖訪問

              當必須以原子操作方式來修改單個值時,互鎖訪問函數(shù)是相當有用的。所謂原子訪問,是指線程在訪問資源時能夠確保所有其他線程都不在同一時間內訪問相同的資源。

              請看下列代碼:

            int globalVar = 0;

            DWORD WINAPI ThreadFunc1(LPVOID n)
            {
             globalVar++;
             return 0;
            }
            DWORD WINAPI ThreadFunc2(LPVOID n)
            {
             globalVar++;
             return 0;
            }

              運行ThreadFunc1和ThreadFunc2線程,結果是不可預料的,因為globalVar++并不對應著一條機器指令,我們看看globalVar++的反匯編代碼:

            00401038 mov eax,[globalVar (0042d3f0)]
            0040103D add eax,1
            00401040 mov [globalVar (0042d3f0)],eax

              在"mov eax,[globalVar (0042d3f0)]" 指令與"add eax,1" 指令以及"add eax,1" 指令與"mov [globalVar (0042d3f0)],eax"指令之間都可能發(fā)生線程切換,使得程序的執(zhí)行后globalVar的結果不能確定。我們可以使用InterlockedExchangeAdd函數(shù)解決這個問題:

            int globalVar = 0;

            DWORD WINAPI ThreadFunc1(LPVOID n)
            {
             InterlockedExchangeAdd(&globalVar,1);
             return 0;
            }
            DWORD WINAPI ThreadFunc2(LPVOID n)
            {
             InterlockedExchangeAdd(&globalVar,1);
             return 0;
            }

              InterlockedExchangeAdd保證對變量globalVar的訪問具有"原子性"。互鎖訪問的控制速度非???,調用一個互鎖函數(shù)的CPU周期通常小于50,不需要進行用戶方式與內核方式的切換(該切換通常需要運行1000個CPU周期)。

              互鎖訪問函數(shù)的缺點在于其只能對單一變量進行原子訪問,如果要訪問的資源比較復雜,仍要使用臨界區(qū)或互斥。

              可等待定時器

              可等待定時器是在某個時間或按規(guī)定的間隔時間發(fā)出自己的信號通知的內核對象。它們通常用來在某個時間執(zhí)行某個操作。

              創(chuàng)建可等待定時器

            HANDLE CreateWaitableTimer(
             PSECURITY_ATTRISUTES psa,
             BOOL fManualReset,//人工重置或自動重置定時器
            PCTSTR pszName);

              設置可等待定時器

              可等待定時器對象在非激活狀態(tài)下被創(chuàng)建,程序員應調用 SetWaitableTimer函數(shù)來界定定時器在何時被激活:

            BOOL SetWaitableTimer(
             HANDLE hTimer, //要設置的定時器
             const LARGE_INTEGER *pDueTime, //指明定時器第一次激活的時間
             LONG lPeriod, //指明此后定時器應該間隔多長時間激活一次
             PTIMERAPCROUTINE pfnCompletionRoutine,
             PVOID PvArgToCompletionRoutine,
            BOOL fResume);

              取消可等待定時器

            BOOl Cancel WaitableTimer(
             HANDLE hTimer //要取消的定時器
            );

              打開可等待定時器

              作為一種內核對象,WaitableTimer也可以被其他進程以名字打開:

            HANDLE OpenWaitableTimer (
             DWORD fdwAccess,
             BOOL bInherithandle,
             PCTSTR pszName
            );

              實例

              下面給出的一個程序可能發(fā)生死鎖現(xiàn)象:

            #include <Windows.h>
            #include <stdio.h>
            CRITICAL_SECTION cs1, cs2;
            long WINAPI ThreadFn(long);
            main()
            {
             long iThreadID;
             InitializeCriticalSection(&cs1);
             InitializeCriticalSection(&cs2);
             CloseHandle(CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)ThreadFn, NULL, 0,&iThreadID));
             while (TRUE)
             {
              EnterCriticalSection(&cs1);
              printf("\n線程1占用臨界區(qū)1");
              EnterCriticalSection(&cs2);
              printf("\n線程1占用臨界區(qū)2");

              printf("\n線程1占用兩個臨界區(qū)");

              LeaveCriticalSection(&cs2);
              LeaveCriticalSection(&cs1);

              printf("\n線程1釋放兩個臨界區(qū)");
              Sleep(20);
             };
             return (0);
            }

            long WINAPI ThreadFn(long lParam)
            {
             while (TRUE)
             {
              EnterCriticalSection(&cs2);
              printf("\n線程2占用臨界區(qū)2");
              EnterCriticalSection(&cs1);
              printf("\n線程2占用臨界區(qū)1");

              printf("\n線程2占用兩個臨界區(qū)");

              LeaveCriticalSection(&cs1);
              LeaveCriticalSection(&cs2);

              printf("\n線程2釋放兩個臨界區(qū)");
              Sleep(20);
             };
            }

              運行這個程序,在中途一旦發(fā)生這樣的輸出:

              線程1占用臨界區(qū)1

              線程2占用臨界區(qū)2

              或

              線程2占用臨界區(qū)2

              線程1占用臨界區(qū)1

              或

              線程1占用臨界區(qū)2

              線程2占用臨界區(qū)1

              或

              線程2占用臨界區(qū)1

              線程1占用臨界區(qū)2

              程序就"死"掉了,再也運行不下去。因為這樣的輸出,意味著兩個線程相互等待對方釋放臨界區(qū),也即出現(xiàn)了死鎖。

              如果我們將線程2的控制函數(shù)改為:

            long WINAPI ThreadFn(long lParam)
            {
             while (TRUE)
             {
              EnterCriticalSection(&cs1);
              printf("\n線程2占用臨界區(qū)1");
              EnterCriticalSection(&cs2);
              printf("\n線程2占用臨界區(qū)2");

              printf("\n線程2占用兩個臨界區(qū)");

              LeaveCriticalSection(&cs1);
              LeaveCriticalSection(&cs2);

              printf("\n線程2釋放兩個臨界區(qū)");
              Sleep(20);
             };
            }

              再次運行程序,死鎖被消除,程序不再擋掉。這是因為我們改變了線程2中獲得臨界區(qū)1、2的順序,消除了線程1、2相互等待資源的可能性。

              由此我們得出結論,在使用線程間的同步機制時,要特別留心死鎖的發(fā)生。
            Posted on 2005-12-30 18:51 艾凡赫 閱讀(1132) 評論(3)  編輯 收藏 引用 所屬分類: 多線程

            Feedback

            # re: Win32多線程程序設計之線程通信 (三)  回復  更多評論   

            2006-03-13 09:44 by kx
            哥們,寫得太好了

            # re: Win32多線程程序設計之線程通信 (三)  回復  更多評論   

            2006-03-14 10:00 by 愛飯盒
            哥們,不好意思是轉載的

            # re: Win32多線程程序設計之線程通信 (三)  回復  更多評論   

            2009-07-14 14:59 by brightcoder
            即使是轉載的,寫的也好!支持!
            欧美亚洲另类久久综合| 国产精品久久久久久五月尺| 久久这里的只有是精品23| 久久精品亚洲AV久久久无码| 久久久久亚洲AV无码观看| 久久国产精品成人片免费| 久久精品成人国产午夜| 欧美粉嫩小泬久久久久久久 | 久久久久久久亚洲Av无码| 97久久久久人妻精品专区 | 国产精品热久久毛片| 久久久久亚洲av综合波多野结衣 | 日韩人妻无码一区二区三区久久99| 欧美日韩久久中文字幕| 国产精品一久久香蕉国产线看| 国内精品久久久久久不卡影院| 久久久久久精品成人免费图片 | 亚洲七七久久精品中文国产| 久久久精品人妻一区二区三区蜜桃 | 久久精品成人免费国产片小草| 久久精品国产色蜜蜜麻豆| 亚洲一区中文字幕久久| 少妇久久久久久被弄高潮| 久久亚洲欧洲国产综合| 麻豆精品久久久一区二区| 欧美精品久久久久久久自慰| 久久婷婷色综合一区二区| 亚洲一区二区三区日本久久九| 久久精品亚洲精品国产色婷| 久久亚洲中文字幕精品一区| 久久午夜无码鲁丝片午夜精品| 91精品国产91久久久久久青草 | 久久久久99精品成人片牛牛影视| 国产午夜精品久久久久免费视| 久久久久se色偷偷亚洲精品av| 久久精品桃花综合| 伊人久久大香线蕉精品不卡| 精品久久综合1区2区3区激情| 久久九九亚洲精品| 伊人久久综合热线大杳蕉下载| 婷婷久久综合九色综合98|