一. 線程通訊----事件:函數
1.一對一模式:ui
#include <stdio.h> #include <stdlib.h> #include <Windows.h> //互斥解決線程衝突 //事件解決線程通訊 //臨界區解決線程衝突 //時間同步線程 HANDLE event[5] = { 0 }; HANDLE hd[5] = { 0 }; DWORD WINAPI Zhang(void *p) { int i = 1; printf("張%d次說:I love you Li.\n", i); Sleep(1000); SetEvent(event[1]); while (++i) { WaitForSingleObject(event[0], INFINITE); //無限等待一個信號 printf("張%d次說:I love you Li.\n", i); Sleep(1000); //ResetEvent(event[0]); //信號復位 SetEvent(event[1]); } return 0; } DWORD WINAPI Li(void *p) { int i = 0; while (++i) { WaitForSingleObject(event[1], INFINITE); //無限等待一個信號 printf("李%d次說:I love you too.\n", i); Sleep(1000); //ResetEvent(event[1]); //信號復位 SetEvent(event[0]); } return 0; } void main() { //第二個參數表明:自動FALSE、手動TRUE(須要reset) //第三個參數信號狀態 //第四個參數標記名稱 //event[0] = CreateEvent(NULL, TRUE, FALSE, NULL); //event[1] = CreateEvent(NULL, TRUE, FALSE, NULL); event[0] = CreateEvent(NULL, FALSE, FALSE, NULL); event[1] = CreateEvent(NULL, FALSE, FALSE, NULL); hd[0] = CreateThread(NULL, 0, Zhang, NULL, 0, NULL); hd[1] = CreateThread(NULL, 0, Li, NULL, 0, NULL); WaitForMultipleObjects(2, hd, TRUE, INFINITE); system("pause"); }
2. 一對一中介者模式:spa
#define _CRT_SECURE_NO_WARNINGS #include <stdio.h> #include <stdlib.h> #include <Windows.h> //互斥解決線程衝突 //事件解決線程通訊 //臨界區解決線程衝突 //時間同步線程 HANDLE event[5] = { 0 }; HANDLE hd[5] = { 0 }; char str[256] = { 0 }; //全局變量,存放說的內容 DWORD WINAPI Wang(void *p) { int i = 0; int k = 0; //判斷是哪一個信號 while (++i) { if (k == 0) { WaitForSingleObject(event[1], INFINITE); //無限等待一個信號 printf("媒婆讀取%d次:%s\n", i,str); Sleep(1000); SetEvent(event[2]); k = 1; } else { WaitForSingleObject(event[3], INFINITE); //無限等待一個信號 printf("媒婆讀取%d次:%s\n", i, str); Sleep(1000); SetEvent(event[0]); k = 0; } } return 0; } DWORD WINAPI Zhang(void *p) { int i = 1; /*printf("張%d次說:I love you Li.\n", i);*/ memset(str, '0', 256); sprintf(str,"張%d次說:I love you Li.\n", i); Sleep(1000); SetEvent(event[1]); while (++i) { WaitForSingleObject(event[0], INFINITE); //無限等待一個信號 /*printf("張%d次說:I love you Li.\n", i);*/ memset(str, '0', 256); sprintf(str,"張%d次說:I love you Li.\n", i); Sleep(1000); //ResetEvent(event[0]); //信號復位 SetEvent(event[1]); } return 0; } DWORD WINAPI Li(void *p) { int i = 0; while (++i) { WaitForSingleObject(event[2], INFINITE); //無限等待一個信號 /*printf("李%d次說:I love you too.\n", i);*/ memset(str, '0', 256); sprintf(str,"李%d次說:I love you too.\n", i); Sleep(1000); //ResetEvent(event[1]); //信號復位 SetEvent(event[3]); } return 0; } void main() { //第二個參數表明:自動FALSE、手動TRUE(須要reset) //第三個參數信號狀態 //第四個參數標記名稱 //event[0] = CreateEvent(NULL, TRUE, FALSE, NULL); //event[1] = CreateEvent(NULL, TRUE, FALSE, NULL); event[0] = CreateEvent(NULL, FALSE, FALSE, NULL); event[1] = CreateEvent(NULL, FALSE, FALSE, NULL); event[2] = CreateEvent(NULL, FALSE, FALSE, NULL); event[3] = CreateEvent(NULL, FALSE, FALSE, NULL); hd[0] = CreateThread(NULL, 0, Zhang, NULL, 0, NULL); hd[1] = CreateThread(NULL, 0, Li, NULL, 0, NULL); hd[2] = CreateThread(NULL, 0, Wang, NULL, 0, NULL); WaitForMultipleObjects(3, hd, TRUE, INFINITE); system("pause"); }
3. 一對多廣播模式:線程
#define _CRT_SECURE_NO_WARNINGS #include <stdio.h> #include <stdlib.h> #include <Windows.h> //互斥解決線程衝突 //事件解決線程通訊 //臨界區解決線程衝突 //時間同步線程 HANDLE event[5] = { 0 }; HANDLE hd[10] = { 0 }; char ch[10] = { 'A','B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J' }; char str[256] = { 0 }; DWORD WINAPI ZhangGirlFriend(void *p) { char *pch = p; printf("I am %c ZhangGirlFrend.\n", *pch); if (*pch == 'A') { MessageBoxA(0, "1", "1", 0); sprintf(str,"張女朋友-%c speak: xiaohaha \n", *pch); SetEvent(event[0]); } int i = 0; while (++i) { WaitForSingleObject(event[0], INFINITE); printf("ZhangGirlFriend-%c read %s\n", *pch, str); Sleep(1000); ResetEvent(event[0]); } return 0; } void main() { //第二個參數表明:自動FALSE(收到一次自動清空一次)、手動TRUE(須要reset) //第三個參數信號狀態 //第四個參數標記名稱 event[0] = CreateEventA(NULL, TRUE, FALSE, "msg"); //一直等待消息 for (int i = 0; i < 10; i++) { hd[i] = CreateThread(NULL, 0, ZhangGirlFriend, &ch[i], 0, NULL); } WaitForMultipleObjects(10, hd, TRUE, INFINITE); system("pause"); }
二. 信號量:指針
1. 信號量用做「關卡」的做用:code
//信號量-->關卡的做用 #include <stdio.h> #include <stdlib.h> #include <Windows.h> #define id "Zhang" #define MAX 3 //0 無限等待 DWORD WINAPI myworker(void *p) { int *pint = p; printf("myworker%d is running...\n", *pint); HANDLE myhsem = OpenSemaphore(SEMAPHORE_ALL_ACCESS, FALSE, id); //打開一個信號 if (myhsem) { printf("myworker%d is waiting...\n", *pint); //初始時信號爲0,爲0就會死鎖,信號量不減 //不爲0的狀況下,信號量-1 if (WaitForSingleObject(myhsem, INFINITE) == WAIT_OBJECT_0) //等到了信號 { printf("myworker%d is getting.\n", *pint); Sleep(3000); printf("myworker%d is leaving.\n", *pint); ReleaseSemaphore(myhsem, 1, NULL);//釋放資源 +1 CloseHandle(myhsem);//執行完成退出 } } return 1; } void main() { //建立信號對象 HANDLE hSEM = CreateSemaphore(NULL, 0, MAX, id);//開闢一個信號,最大計數是3 int a[10] = { 0,1,2,3,4,5,6,7,8,9 }; HANDLE hd[10] = { 0 }; for (int i = 0; i < 10; i++) { hd[i] = CreateThread(NULL, 0, myworker, a + i, 0, NULL); //建立10個線程 } Sleep(5000); printf("激活線程.\n"); ReleaseSemaphore(hSEM, MAX, NULL);//最多一次放過3個 +3 WaitForMultipleObjects(10, hd, TRUE, INFINITE); CloseHandle(hSEM); system("pause"); }
2. 信號量實現互斥:對象
#include <stdio.h> #include <stdlib.h> #include <Windows.h> int num = 0; //互斥量,只能讓一個線程運行,其餘休眠 //信號量,能夠讓多個線程運行,其餘線程休眠 //臨界區,只能讓一個線程運行,其餘休眠 //原子操做,操做速度最快 //事件也能夠實現互斥 DWORD WINAPI add(void *p) { HANDLE myhsem = OpenSemaphore(SEMAPHORE_ALL_ACCESS, FALSE, "Hello"); if (myhsem) { if (WaitForSingleObject(myhsem, INFINITE) == WAIT_OBJECT_0) //等到了信號 { for (int i = 0; i < 10000; i++) { num++; } ReleaseSemaphore(myhsem, 1, NULL);//釋放資源 +1 CloseHandle(myhsem);//執行完成退出 } } else { printf("信號量獲取失敗.\n"); } return 1; } void main() { HANDLE hSEM = CreateSemaphore(NULL, 0, 1, "Hello"); HANDLE hd[64] = { 0 }; for (int i = 0; i < 64; i++) { hd[i] = CreateThread(NULL, 0, add, NULL, 0, NULL); //建立64個線程 } Sleep(2000); printf("激活線程.\n"); ReleaseSemaphore(hSEM, 1, NULL); //一次放過一個 WaitForMultipleObjects(64, hd, TRUE, INFINITE); printf("%d\n", num); CloseHandle(hSEM); system("pause"); }
三. 互斥鎖:blog
相關函數以下:進程
第一個 InitializeSRWLock
函數功能:初始化讀寫鎖
函數原型:VOID InitializeSRWLock(PSRWLOCK SRWLock);
函數說明:初始化(沒有刪除或銷燬SRWLOCK的函數,系統會自動清理)事件
第二個 AcquireSRWLockExclusive
函數功能:寫入者線程申請寫資源。
函數原型:VOID AcquireSRWLockExclusive(PSRWLOCK SRWLock);
第三個 ReleaseSRWLockExclusive
函數功能:寫入者線程寫資源完畢,釋放對資源的佔用。
函數原型:VOID ReleaseSRWLockExclusive(PSRWLOCK SRWLock);
第四個 AcquireSRWLockShared
函數功能:讀取者線程申請讀資源。
函數原型:VOID AcquireSRWLockShared(PSRWLOCK SRWLock);
第五個 ReleaseSRWLockShared
函數功能:讀取者線程結束讀取資源,釋放對資源的佔用。
函數原型:VOID ReleaseSRWLockShared(PSRWLOCK SRWLock);
#include <stdio.h> #include <stdlib.h> #include <Windows.h> int num = 6400000; SRWLOCK g_lock; //注意一個線程僅能鎖定資源一次,不能屢次鎖定資源。 DWORD WINAPI read(void *p) { AcquireSRWLockShared(&g_lock); //讀取期間鎖定數據,數據沒法被修改 int i = 0; while (1) { Sleep(1000); printf("第%d秒num=%d\n", i, num); if (i == 10) { break; } i++; } ReleaseSRWLockShared(&g_lock); return 1; } //改變一個變量的時候須要鎖定 DWORD WINAPI write(void *p) { AcquireSRWLockExclusive(&g_lock); //鎖定寫入 printf("開始寫入...\n"); for (int i = 0; i < 100000; i++) { num--; //Sleep(10); } ReleaseSRWLockExclusive(&g_lock); printf("結束寫入...\n"); return 1; } void main() { InitializeSRWLock(&g_lock); //初始化互斥鎖 CreateThread(NULL, 0, read, NULL, 0, NULL); HANDLE hd[64]; for (int i = 0; i < 64; i++) { hd[i] = CreateThread(NULL, 0, write, NULL, 0, NULL); } WaitForMultipleObjects(64, hd, TRUE, INFINITE); printf("last=%d\n", num); system("pause"); }
四. 跨進程通訊:
1. 信號量mutex 跨進程通訊:
文件mutex1.c :
#include <stdio.h> #include <stdlib.h> #include <Windows.h> char name[100] = "Zhang love Li"; void main() { HANDLE mutex = OpenMutexA(MUTEX_ALL_ACCESS, TRUE, name); if (mutex == NULL) { printf("打開失敗!\n"); system("pause"); return; } printf("等待------\n"); DWORD res = WaitForSingleObject(mutex, 10000); switch (res) { case WAIT_OBJECT_0: printf("收到信號---\n"); break; case WAIT_TIMEOUT: printf("超時沒有收到---\n"); break; case WAIT_ABANDONED: printf("另一個進程意外終止---\n"); break; default: break; } CloseHandle(mutex); system("pause"); }
文件mutex2.c :
#include <stdio.h> #include <stdlib.h> #include <Windows.h> char name[100] = "Zhang love Li"; void main() { HANDLE mutex = CreateMutexA(NULL, TRUE, name); printf("建立成功!\n"); char ch = getchar(); ReleaseMutex(mutex); //離開互斥區 printf("觸發互斥量.\n"); CloseHandle(mutex); system("pause"); }
運行結果:
2. 事件 event 跨進程通訊:
文件event.c :
#include <stdio.h> #include <stdlib.h> #include <Windows.h> char name[100] = "Zhang love Li"; //只有mutex能夠感知丟失,event沒法感知 void main() { HANDLE event = CreateEventA(NULL, FALSE, FALSE, name); printf("建立成功!\n"); char ch = getchar(); SetEvent(event); printf("觸發event.\n"); CloseHandle(event); system("pause"); }
文件 wait.c :
#include <stdio.h> #include <stdlib.h> #include <Windows.h> char name[100] = "Zhang love Li"; void main() { HANDLE event = OpenEventA(EVENT_ALL_ACCESS, TRUE, name);//打開事件 if (event == NULL) { printf("打開失敗!\n"); system("pause"); return; } printf("等待------\n"); DWORD res = WaitForSingleObject(event, 10000); switch (res) { case WAIT_OBJECT_0: printf("收到信號---\n"); break; case WAIT_TIMEOUT: printf("超時沒有收到---\n"); break; case WAIT_ABANDONED: printf("另一個進程意外終止---\n"); break; default: break; } CloseHandle(event); system("pause"); }
3. 信號 semaphore 跨進程通訊:
semaphore.c :
#include <stdio.h> #include <stdlib.h> #include <Windows.h> char name[100] = "Zhang love Li"; //只有mutex能夠感知丟失,event沒法感知 void main() { HANDLE hsem = CreateSemaphoreA(NULL, 0, 1, name); printf("建立成功!\n"); char ch = getchar(); ReleaseSemaphore(hsem, 1, NULL); printf("觸發信號量semaphore.\n"); CloseHandle(hsem); system("pause"); }
wait.c :
#include <stdio.h> #include <stdlib.h> #include <Windows.h> char name[100] = "Zhang love Li"; void main() { HANDLE hsem = OpenSemaphoreA(SEMAPHORE_ALL_ACCESS, TRUE, name); if (hsem == NULL) { printf("打開失敗!\n"); system("pause"); return; } printf("等待------\n"); DWORD res = WaitForSingleObject(hsem, 10000); switch (res) { case WAIT_OBJECT_0: printf("收到信號---\n"); break; case WAIT_TIMEOUT: printf("超時沒有收到---\n"); break; case WAIT_ABANDONED: printf("另一個進程意外終止---\n"); break; default: break; } CloseHandle(hsem); system("pause"); }
五. 回調函數與定時器:
#include <stdio.h> #include <stdlib.h> #include <Windows.h> //回調函數,函數指針能夠來調用 VOID CALLBACK timerun(void *parg, DWORD timearg, DWORD timehigh) { DWORD dwindex = *(DWORD *)parg; printf("第%d次\n", dwindex); } void main() { HANDLE timer1 = CreateWaitableTimerA(NULL, TRUE, "hello");//建立時鐘 if (timer1 == NULL) { printf("建立失敗!\n"); } LARGE_INTEGER mytime; mytime.QuadPart = -50000000; //單位是0.1微秒 DWORD dwparam = 1; //設置定時器 if (SetWaitableTimer(timer1, &mytime, 1000, timerun, &dwparam, FALSE))//1000 1秒循環一次 { printf("等待5秒後開始幹活!\n"); for (int i = 0; i < 15; i++, dwparam++) //循環調用多少次 { SleepEx(INFINITE, TRUE); } } CancelWaitableTimer(timer1);//取消定時器 CloseHandle(timer1); system("pause"); }
六. 原子操做:
#include <stdio.h> #include <stdlib.h> void main() { volatile int i = 10; //數據被意外改變的時候,強制讀內存 int a = i; printf("i=%d\n", a); //偷偷改變i __asm { mov dword ptr[ebp-4],20h //16進制 20h=32 } int b = i; printf("i=%d\n", b); system("pause"); }
上面結果在Debug模式下結果爲:
在Release模式下結果爲: