प्रौद्योगिकी साझेदारी

WIN32 कोर प्रोग्रामिंग - थ्रेड ऑपरेशन (2) समकालिक परस्पर बहिष्कार

2024-07-12

한어Русский языкEnglishFrançaisIndonesianSanskrit日本語DeutschPortuguêsΕλληνικάespañolItalianoSuomalainenLatina

सामग्रीसूची

जातिस्थितिः

आलोचनात्मकखण्डः

म्यूटेक्स

आलोचनात्मकखण्ड एवं म्यूटेक्स

सेमाफोर

घटना


जातिस्थितिः

  • बहुसूत्रयुक्ते वातावरणे यदा बहुविधाः सूत्राः एकस्मिन् समये समानदत्तांशं अभिगच्छन्ति वा परिवर्तयन्ति वा तदा अन्तिमपरिणामः सूत्रनिष्पादनसमयः भवति ।

  • यदि समन्वयनतन्त्रं नास्ति तर्हि जातिस्थितयः भविष्यन्ति, येन अशुद्धदत्तांशः अथवा कार्यक्रमअपवादः भवितुम् अर्हति ।

  1. #include <iostream>
  2. #include <windows.h>
  3. DWORD g_Num = 0;
  4. DWORD WINAPI WorkThread(LPVOID lp)
  5. {
  6. for (size_t i = 0; i < 10000000; i++)
  7. {
  8. //g_Num++;
  9. __asm LOCK INC [g_Num]
  10. }
  11. return 0;
  12. }
  13. int main()
  14. {
  15. HANDLE hThread[2] = { 0 };
  16. hThread[0] = CreateThread(NULL, 0, WorkThread, NULL, 0, NULL);
  17. hThread[1] = CreateThread(NULL, 0, WorkThread, NULL, 0, NULL);
  18. WaitForMultipleObjects(2, hThread, TRUE, -1);
  19. std::cout << g_Num << std::endl;
  20. return 0;
  21. }

आलोचनात्मकखण्डः

  1. #include <iostream>
  2. #include <windows.h>
  3. DWORD g_Num = 0;
  4. CRITICAL_SECTION cs = { 0 };
  5. DWORD WINAPI WorkThread(LPVOID lp)
  6. {
  7. for (size_t i = 0; i < 1000000; i++)
  8. {
  9. // 进入临界区
  10. EnterCriticalSection(&cs);
  11. // TODO
  12. g_Num++;
  13. // 退出临界区
  14. LeaveCriticalSection(&cs);
  15. }
  16. return 0;
  17. }
  18. int main()
  19. {
  20. HANDLE hThread[2] = { 0 };
  21. // 初始临界区
  22. InitializeCriticalSection(&cs);
  23. hThread[0] = CreateThread(NULL, 0, WorkThread, NULL, 0, NULL);
  24. hThread[1] = CreateThread(NULL, 0, WorkThread, NULL, 0, NULL);
  25. WaitForMultipleObjects(2, hThread, TRUE, -1);
  26. std::cout << g_Num << std::endl;
  27. // 清理临界区
  28. DeleteCriticalSection(&cs);
  29. return 0;
  30. }

म्यूटेक्स

  • Mutex (Mutex) इत्यस्य उपयोगः बहुविधधागानां एकस्मिन् समये साझासंसाधनानाम् अभिगमनं परिवर्तनं वा निवारयितुं भवति ।

  • केवलं एकः सूत्रः एव म्यूटेक्सस्य स्वामित्वं कर्तुं शक्नोति यदि एकः सूत्रः म्यूटेक्सस्य स्वामित्वं गृह्णाति तर्हि म्यूटेक्स् इत्यस्य अनुरोधं कुर्वन्तः अन्ये सूत्राः यावत् म्यूटेक्स् अनुमतिः न मुक्ताः न भवति तावत् अवरुद्धाः भविष्यन्ति ।

  • एकं म्यूटेक्सं रचयन्तु - CreateMutex

  • म्यूटेक्स इत्यस्य अनुरोधः - WaitForSingleObject

  • म्यूटेक्सं मुक्तं कुर्वन्तु - ReleaseMutex

  1. #include <iostream>
  2. #include <windows.h>
  3. HANDLE hMutex = 0;
  4. DWORD g_Num = 0;
  5. DWORD WINAPI WorkThread(LPVOID lp)
  6. {
  7. for (size_t i = 0; i < 100000; i++)
  8. {
  9. WaitForSingleObject(hMutex, INFINITE);
  10. g_Num++;
  11. ReleaseMutex(hMutex);
  12. }
  13. return 0;
  14. }
  15. int main()
  16. {
  17. hMutex = CreateMutex(NULL, FALSE, NULL);
  18. HANDLE hThread1 = CreateThread(NULL, 0, WorkThread, NULL, 0, NULL);
  19. HANDLE hThread2 = CreateThread(NULL, 0, WorkThread, NULL, 0, NULL);
  20. WaitForSingleObject(hThread1, INFINITE);
  21. WaitForSingleObject(hThread2, INFINITE);
  22. CloseHandle(hThread1);
  23. CloseHandle(hThread2);
  24. CloseHandle(hMutex);
  25. std::cout << g_Num << std::endl;
  26. return 0;
  27. }

आलोचनात्मकखण्ड एवं म्यूटेक्स

  • आलोचनात्मकः खण्डः

    • साझासंसाधनानाम् कृते सूत्रसमन्वयनतन्त्रम्, महत्त्वपूर्णखण्डाः समानप्रक्रियायाः सूत्राणां मध्ये परस्परं अनन्यप्रवेशं प्रदास्यन्ति ।

    • प्रत्येकं सूत्रं साझासंसाधनानाम् अभिगमनात् पूर्वं महत्त्वपूर्णविभागे प्रवेशं कर्तुं समर्थः भवितुमर्हति, तथा च सूत्रसमन्वयनं पूर्णं कर्तुं अभिगमनस्य समाप्तेः अनन्तरं महत्त्वपूर्णखण्डं त्यक्त्वा गन्तुं शक्नोति

  • mutex इति

    • एकस्मिन् समये साझासंसाधनानाम् अभिगमनं बहुविधं थ्रेड् प्रतिबन्धयितुं थ्रेड् समन्वयनतन्त्रस्य उपयोगः भवति ।

    • म्यूटेक्स् प्रक्रियां वा थ्रेड् वा समन्वययितुं शक्नुवन्ति, प्रक्रियासु समन्वयं कर्तुं च शक्नुवन्ति ।
      1. #include <iostream>
      2. #include <Windows.h>
      3. int main()
      4. {
      5. HANDLE hMutex = CreateMutex(NULL, FALSE, L"0xCC_Mutex");
      6. if (hMutex == NULL) return 0;
      7. if (GetLastError() == ERROR_ALREADY_EXISTS)
      8. {
      9. MessageBox(NULL, L"禁止多开", L"错误", MB_OKCANCEL);
      10. return 0;
      11. }
      12. std::cout << "Game Start..." << std::endl;
      13. system("pause");
      14. CloseHandle(hMutex);
      15. return 0;
      16. }
  • प्रदर्शनम्‌

    • समानप्रक्रियायाः सूत्राणाम् अन्तः म्यूटेक्स् इत्यस्मात् समीक्षात्मकाः विभागाः द्रुततराः भवन्ति ।

  • नियोग

    • म्यूटेक्स्स् प्रक्रियासु समन्वयितुं शक्यन्ते, परन्तु महत्त्वपूर्णखण्डाः केवलं एकस्मिन् प्रक्रियायां थ्रेड् मध्ये समन्वयितुं शक्यन्ते ।

  • स्वामित्वम्

    • म्यूटेक्स् इत्यस्य स्वामित्वस्य कठोरता आवश्यकी भवति, केवलं म्यूटेक्स् अनुमतियुक्ताः सूत्राः एव तत् मुक्तुं शक्नुवन्ति ।

  • गतिरोध
    • यदा सूत्रं तालं धारयन् अप्रत्याशितरूपेण म्रियते (अपवादः) ।
    • यदि कश्चन सूत्रः गम्भीरखण्डस्य तालं धारयन् अप्रत्याशितरूपेण समाप्तः भवति तर्हि ताला न मुक्तः भविष्यति, येन गम्भीरखण्डस्य प्रतीक्षमाणाः अन्ये सूत्राः सामान्यतया निष्पादयितुं असमर्थाः भवन्ति, यस्य परिणामेण गतिरोधः भवति
      1. #include <iostream>
      2. #include <Windows.h>
      3. CRITICAL_SECTION CriticalSection = { 0 };
      4. DWORD WINAPI WorkThread(LPVOID lp)
      5. {
      6. EnterCriticalSection(&CriticalSection);
      7. printf("TID -> %d rn", GetCurrentThreadId());
      8. Sleep(5000);
      9. LeaveCriticalSection(&CriticalSection);
      10. return 0;
      11. }
      12. int main()
      13. {
      14. InitializeCriticalSection(&CriticalSection);
      15. HANDLE hThread1 = CreateThread(NULL, 0, WorkThread, NULL, 0, NULL);
      16. Sleep(1000);
      17. TerminateThread(hThread1, 1);
      18. HANDLE hThread2 = CreateThread(NULL, 0, WorkThread, NULL, 0, NULL);
      19. WaitForSingleObject(hThread2, INFINITE);
      20. DeleteCriticalSection(&CriticalSection);
      21. return 0;
      22. }
    • यदि म्यूटेक्स-लॉक् धारयन् कश्चन सूत्रः अप्रत्याशितरूपेण समाप्तः भवति तर्हि विण्डोज स्वयमेव स्वस्य स्वामित्वं मुक्तं करोति येन अन्ये थ्रेड् सामान्यतया निष्पादनं निरन्तरं कर्तुं शक्नुवन्ति ।
      1. #include <iostream>
      2. #include <Windows.h>
      3. HANDLE hMutex = NULL;
      4. DWORD WINAPI WorkThread1(LPVOID lp)
      5. {
      6. WaitForSingleObject(hMutex, INFINITE);
      7. printf("TID -> %d rn", GetCurrentThreadId());
      8. Sleep(5000);
      9. TerminateThread(GetCurrentThread(), -1);
      10. //todo
      11. return 0;
      12. }
      13. DWORD WINAPI WorkThread2(LPVOID lp)
      14. {
      15. printf("Wait For Thread1 Leavern");
      16. WaitForSingleObject(hMutex, INFINITE);
      17. printf("TID -> %d rn", GetCurrentThreadId());
      18. ReleaseMutex(hMutex);
      19. return 0;
      20. }
      21. int main()
      22. {
      23. hMutex = CreateMutex(NULL, FALSE, NULL);
      24. HANDLE hThread1 = CreateThread(NULL, 0, WorkThread1, NULL, 0, NULL);
      25. Sleep(1000);
      26. HANDLE hThread2 = CreateThread(NULL, 0, WorkThread2, NULL, 0, NULL);
      27. WaitForSingleObject(hThread2, INFINITE);
      28. CloseHandle(hMutex);
      29. CloseHandle(hThread1);
      30. CloseHandle(hThread2);
      31. return 0;
      32. }

सेमाफोर

  • सेमाफोर् इति समन्वयनवस्तु यस्य उपयोगः बहुभिः सूत्रैः साझासंसाधनानाम् अभिगमनं नियन्त्रयितुं भवति । उपलब्धानां संसाधनानाम् परिमाणं प्रतिनिधियति इति गणकः अस्ति । यदा सेमाफोरस्य मूल्यं 0 इत्यस्मात् अधिकं भवति तदा एतत् सूचयति यत् यदा मूल्यं 0 भवति तदा संसाधनं उपलब्धं नास्ति इति सूचयति;

    • प्रतीक्षतु : सेमाफोरस्य मूल्यं न्यूनीकर्तुं प्रयतते। यदि सेमाफोरस्य मूल्यं 0 इत्यस्मात् अधिकं भवति तर्हि 1 इत्यनेन न्यूनीकृत्य निष्पादनं निरन्तरं कुर्वन्तु । यदि सेमाफोरस्य मूल्यं 0 भवति तर्हि यावत् सेमाफोरस्य मूल्यं 0 इत्यस्मात् अधिकं न भवति तावत् सूत्रं अवरुद्धं करोति ।

    • मुक्तः : सेमाफोरस्य मूल्यं वर्धयन्तु। यदि अन्ये सूत्राः अवरुद्धाः सन्ति ये अस्य सेमाफोरस्य प्रतीक्षां कुर्वन्ति तर्हि तेषु एकः जागरितः भविष्यति ।

  • सेमाफोर रचयन्तु

    • विण्डोज-प्रणालीषु, उपयोगं कुर्वन्तु CreateSemaphore वाCreateSemaphoreEx फंक्शन् सेमाफोर् निर्माति ।

  • प्रतीक्ष्यताम् (Wait) तथा (Release) सेमाफोरं मुक्तं कुर्वन्तु

    • सेमाफोर् इत्यत्र प्रतीक्षा प्रायः उपयोगेन क्रियते WaitForSingleObject वाWaitForMultipleObjects नियोग।

    • सेमाफोरप्रयोगं विमोचयन्तु ReleaseSemaphore नियोग।

  1. #include <iostream>
  2. #include <Windows.h>
  3. #define MAX_COUNT_SEMAPHORE 3
  4. HANDLE g_SemapHore = NULL;
  5. HANDLE g_hThreadArr[10] = { 0 };
  6. DWORD WINAPI WorkThread(LPVOID lp)
  7. {
  8. WaitForSingleObject(g_SemapHore, INFINITE);
  9. for (size_t i = 0; i < 10; i++)
  10. {
  11. std::cout << "COUNT -> " << (int)lp << std::endl;
  12. Sleep(500);
  13. }
  14. ReleaseSemaphore(g_SemapHore, 1, NULL);
  15. return 0;
  16. }
  17. int main()
  18. {
  19. g_SemapHore = CreateSemaphore(
  20. NULL, //安全属性
  21. MAX_COUNT_SEMAPHORE, //初始计数
  22. MAX_COUNT_SEMAPHORE, //最大计数
  23. NULL //信号名称
  24. );
  25. if (g_SemapHore == NULL)
  26. {
  27. std::cout << GetLastError() << std::endl;
  28. return 1;
  29. }
  30. for (size_t i = 0; i < 10; i++)
  31. {
  32. g_hThreadArr[i] = CreateThread(
  33. NULL,
  34. 0,
  35. WorkThread,
  36. (LPVOID)i,
  37. 0,
  38. NULL
  39. );
  40. }
  41. WaitForMultipleObjects(10, g_hThreadArr, TRUE, INFINITE);
  42. //closehandle
  43. return 0;
  44. }

घटना

  • विण्डोज प्रोग्रामिंग् इत्यस्मिन् इवेण्ट् इति समन्वयनतन्त्रं बहुसूत्राणां मध्ये संकेतं प्रेषयितुं प्रयुक्तम् ।इवेण्ट् ऑब्जेक्ट् भवितुम् अर्हतिमैनुअल रीसेटवास्वचालितं पुनः सेट् करणीयम्

    • मैनुअल् रीसेट् इवेण्ट्: यदा कश्चन इवेण्ट् सेट् (संकेतः) भवति तदा सः स्पष्टतया रीसेट् यावत् अस्मिन् अवस्थायां एव तिष्ठति । अस्य अर्थः अस्ति यत् घटनायाः प्रतीक्षमाणाः बहुविधाः सूत्राः घटनायाः पुनःस्थापनात् पूर्वं जागृतुं शक्यन्ते ।

    • Auto Reset Event: यदा प्रतीक्षमाणेन थ्रेड् द्वारा कश्चन इवेण्ट् प्राप्तः (संकेतः) भवति तदा प्रणाली स्वयमेव घटनास्थितिं गैर-संकेतयुक्तं (असंकेतं) इति रीसेट् करोति । एकस्मिन् समये एकमेव सूत्रं जागरितव्यमिति भावः ।

  • घटना रचयन्तु

    • विण्डोज एपिआइ कार्याणां उपयोगःCreateEventइवेण्ट् ऑब्जेक्ट् निर्मातुं शक्यते

    • lpEventAttributes: सुरक्षाविशेषणस्य सूचकः, यदि सेट् भवतिNULL, पूर्वनिर्धारितसुरक्षा उपयुज्यते ।

    • bManualReset: यदिTRUE, ततः मैनुअल् रीसेट् इवेण्ट् निर्मीयते, अन्यथा स्वयमेव रीसेट् इवेण्ट् निर्मीयते ।

    • bInitialState: यदिTRUE, तर्हि प्रारम्भिकावस्था संकेतावस्था यदि;FALSE, असंकेतावस्था अस्ति ।

    • lpName: आयोजनस्य नाम।

  • इवेण्ट् सेट् कर्तुं (इवेण्ट् स्टेट् इत्येतत् सिग्नल् स्टेट् इत्यत्र सेट् कर्तुं) उपयोगं कुर्वन्तुSetEventनियोग

  • घटनां पुनः सेट् कर्तुं (घटनास्थितिं अ-संकेतस्थितौ सेट् कर्तुं) उपयोगं कुर्वन्तुResetEventनियोग

  • इवेण्ट् इत्यस्य प्रतीक्षां कुर्वन्तु यत् इवेण्ट् ऑब्जेक्ट् इत्यस्य सिग्नल् स्टेट् भवितुं प्रतीक्षां कुर्वन्तु ।WaitForSingleObjectनियोग

  1. #include <iostream>
  2. #include <Windows.h>
  3. DWORD WINAPI WorkThread(LPVOID lp)
  4. {
  5. HANDLE hEvent = *(HANDLE*)lp;
  6. std::cout << "Thread - " << GetCurrentThreadId() << " Waiting For Event" << std::endl;
  7. WaitForSingleObject(hEvent, INFINITE);
  8. std::cout << "Thread - " << GetCurrentThreadId() << " actived" << std::endl;
  9. return 0;
  10. }
  11. int main()
  12. {
  13. HANDLE hThreads[3] = { 0 };
  14. HANDLE hEvent = NULL;
  15. hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
  16. if (hEvent == NULL) return 0;
  17. for (size_t i = 0; i < 3; i++)
  18. {
  19. hThreads[i] = CreateThread(NULL, 0, WorkThread, &hEvent, 0, NULL);
  20. }
  21. Sleep(2000);
  22. SetEvent(hEvent);
  23. WaitForMultipleObjects(3, hThreads, TRUE, INFINITE);
  24. CloseHandle(hEvent);
  25. return 0;
  26. }