前面, 我们把消息队列存取都放在主线程中, 而在实际应用中, 很多时候, 存消息队列在主线程, 取消息队列在其他线程(如网络线程)。 下面, 我们将之前的程序改为多线程程序:
#include <windows.h> #include <iostream> using namespace std; #define Rectangle MyRectangle // 避免Rectangle与Windows中的Rectangle冲突 // 对象的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) { Node *pn = new Node; Node *qn = NULL; Basic *p = pb->copy(); // 多态性 if(NULL == head) { head = pn; } else { qn = head; while(NULL != qn->next) { qn = qn->next; } qn->next = pn; } pn->pBasic = p; // 千万别忘记啊 pn->next = NULL; // 千万别忘记啊 return head; } // 从链式消息队列中取出消息(结点) Node *getMsgFromQueue() { if(NULL == head) { return NULL; } Node *pn = head; head = head->next; 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); // 定义三个对象并赋值 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); } return 0; }结果为:
11
22
33
44
55
66
77
11
22
33
44
55
66
77
11
22
33
44
55
66
77
11
22
33
44
55
66
77
11
22
33
44
55
66
77
11
22
33
44
55
66
77
11
22
33
44
55
66
77
11
22
33
44
55
66
77
11
22
33
44
55
66
77
11
22
33
44
55
66
77
11
22
33
44
55
66
77
11
22
33
44
55
66
77
11
22
33
44
55
66
77
11
22
33
44
55
66
77
11
22
33
44
55
66
77
11
22
33
44
55
66
77
11
22
33
44
55
66
77
11
22
33
44
55
66
77
11
22
33
44
55
66
77
11
22
33
44
55
66
77
11
22
33
44
55
66
77
11
22
33
44
55
66
77
11
22
33
44
55
66
77
...
看似得到了正确的结果, 但是, 上述程序是有问题的, 加入主线程正在存, 子线程正在取, 那岂不是乱套了么。 当然, 上面的程序侥幸没有出现这种情况, 为了说明这种情况, 我在addToMsgQueue函数中, 故意加一个睡眠语句, 再看看:
#include <windows.h> #include <iostream> using namespace std; #define Rectangle MyRectangle // 避免Rectangle与Windows中的Rectangle冲突 // 对象的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) { Node *pn = new Node; Node *qn = NULL; Basic *p = pb->copy(); // 多态性 if(NULL == head) { head = pn; } else { qn = head; while(NULL != qn->next) { qn = qn->next; } Sleep(20); // 故意加的语句, 用于构造异常场景 qn->next = pn; } pn->pBasic = p; // 千万别忘记啊 pn->next = NULL; // 千万别忘记啊 return head; } // 从链式消息队列中取出消息(结点) Node *getMsgFromQueue() { if(NULL == head) { return NULL; } Node *pn = head; head = head->next; 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); // 定义三个对象并赋值 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); } return 0; }程序结果为:
11
44
55
66
77
11
22
33
44
55
66
77
...
看看,看看, 产生异常了吧, 主要原因是线程不同步问题, 在后续博文中, 我们将介绍线程安全的情况, 那时, 我们将考虑线程同步。