多執行緒環境下安全的訊息佇列存取---利用訊號量
阿新 • • 發佈:2019-02-01
前面幾篇博文中, 我們一直在討論異質連結串列訊息佇列問題, 在本文中, 我們繼續來探討這一問題, 在多執行緒環境下, 考慮執行緒同步問題, 程式碼如下(我用Sleep(20);來故意搗亂):
測試過十幾次, 沒發現程式有什麼問題。 如果大家有不同意見, 可以提出。#include <windows.h> #include <iostream> using namespace std; #define Rectangle MyRectangle // 避免Rectangle與Windows中的Rectangle衝突 HANDLE g_hSemp = NULL; // 訊號量handle // 物件的id值 typedef enum { ErrorId = -1, IntegerId = 1, PointId = 2, RectangeId = 3, }ObjectID; // 基類 struct Basic { ObjectID id; virtual Basic *copy() = 0; // 純虛擬函式 }; // 整數類 struct Integer : public Basic { int a; Basic *copy() { Integer *p = new Integer; p->a = ((Integer*)this)->a; p->id = ((Integer*)this)->id; return p; } }; // 點類 struct Point : public Basic { int x; int y; Basic *copy() { Point *p = new Point; p->x = ((Point*)this)->x; p->y = ((Point*)this)->y; p->id = ((Point*)this)->id; return p; } }; // 矩形類 struct Rectangle : public Basic { Point point; int width; int height; Basic *copy() { Rectangle *p = new Rectangle; p->point.x = ((Rectangle*)this)->point.x; p->point.y = ((Rectangle*)this)->point.y; p->width = ((Rectangle*)this)->width; p->height = ((Rectangle*)this)->height; p->id = ((Rectangle*)this)->id; return p; } }; // 抽象物件的共同點, 構造成新的結點, 便於連結 typedef struct node { node *next; Basic *pBasic; }Node; Node *head = NULL; // 指向第一結點(採用不帶頭結點的連結串列) // 往鏈式訊息佇列中塞訊息 Node *addToMsgQueue(Basic* pb) { WaitForSingleObject(g_hSemp, INFINITE); printf("add\n"); Node *pn = new Node; Node *qn = NULL; Basic *p = pb->copy(); // 多型性 if(NULL == head) { Sleep(20); head = pn; } else { qn = head; while(NULL != qn->next) { Sleep(20); qn = qn->next; } Sleep(20); qn->next = pn; } pn->pBasic = p; // 千萬別忘記啊 pn->next = NULL; // 千萬別忘記啊 ReleaseSemaphore(g_hSemp, 1, NULL); return head; } // 從鏈式訊息佇列中取出訊息(結點) Node *getMsgFromQueue() { WaitForSingleObject(g_hSemp, INFINITE); printf("get\n"); if(NULL == head) { Sleep(20); ReleaseSemaphore(g_hSemp, 1, NULL); return NULL; } Node *pn = head; head = head->next; Sleep(20); ReleaseSemaphore(g_hSemp, 1, NULL); return pn; } // 執行緒函式 DWORD WINAPI ThreadFun(LPVOID pM) { Node *p = NULL; // 從訊息佇列中取出訊息 while(1) { p = getMsgFromQueue(); if(NULL == p) { Sleep(100); continue; } // 對指標進行還原 switch(p->pBasic->id) { case IntegerId: { cout << ((Integer*)(p->pBasic))->a << endl; break; } case PointId: { cout << ((Point *)(p->pBasic))->x << endl; cout << ((Point *)(p->pBasic))->y << endl; break; } case RectangeId: { cout << ((Rectangle *)(p->pBasic))->point.x << endl; cout << ((Rectangle *)(p->pBasic))->point.y << endl; cout << ((Rectangle *)(p->pBasic))->width << endl; cout << ((Rectangle *)(p->pBasic))->height << endl; break; } default: { break; } } } return 0; } // 主執行緒 int main() { HANDLE handle = CreateThread(NULL, 0, ThreadFun, NULL, 0, NULL); CloseHandle(handle); g_hSemp = CreateSemaphore(NULL, 1, 10, NULL); // 定義三個物件並賦值 Integer i; Point po; Rectangle rect; i.id = IntegerId; po.id = PointId; rect.id = RectangeId; i.a = 11; po.x = 22; po.y = 33; rect.point.x = 44; rect.point.y = 55; rect.width = 66; rect.height = 77; // 塞入訊息佇列 while(1) { addToMsgQueue(&i); addToMsgQueue(&po); addToMsgQueue(&rect); Sleep(2000); } CloseHandle(g_hSemp); return 0; }
貌似該睡覺了啊。