首页 > 代码库 > 多线程编程1
多线程编程1
参考资料:
http://blog.csdn.net/JXH_123/article/details/23450031 秒杀多线程系列
http://www.baidu.com/index.php?tn=utf8kb_oem_dg&addresssearch=1#wd=C%2B%2B%E5%BE%AA%E7%8E%AF%E6%B6%88%E6%81%AF%E9%98%9F%E5%88%97&ie=utf-8&tn=utf8kb_oem_dg&f=8&rsv_bp=1&rsv_spt=1&rsv_n=2&rsv_sug3=32&rsv_sug4=1431&rsv_sug1=17&rsv_sug2=0&inputT=3750&bs=%E5%BE%AA%E7%8E%AF%E6%B6%88%E6%81%AF%E9%98%9F%E5%88%97 c++消息循环队列 (没用到)
http://www.cnblogs.com/egmkang/archive/2012/11/17/2763295.html 合理的设计与使用消息队列
http://blog.csdn.net/yand789/article/details/17095993 UDP多线程通信server程序
http://blog.csdn.net/no_mame/article/details/17437273 UDP 多线程客户端与单线程服务器端
http://so.csdn.net/search?utf8=%E2%9C%93&t=&q=+udp%E5%A4%9A%E7%BA%BF%E7%A8%8B&commit=%E6%90%9C+%E7%B4%A2&sort= WaitforMultipleObjects 使用详解
http://blog.csdn.net/lyd_253261362/article/details/4450202 WaitforMultipleObjects 使用详解
http://bbs.csdn.net/topics/30350133 请教关于WaitforMultipleObjects的用法
http://blog.csdn.net/chw1989/article/details/7453217 多线程套接字编程
http://www.baidu.com/s?ie=utf-8&bs=CreateEvent&f=8&rsv_bp=1&wd=CreateEvent+%E7%94%A8%E6%B3%95%E8%AF%A6%E8%A7%A3&rsv_sug3=4&rsv_sug4=161&rsv_sug1=2&rsv_sug2=0&inputT=7745 CreateEvent用法详解
http://www.cnblogs.com/shootingstars/archive/2004/07/15/24602.html 在主线程中慎用WaitforMultipleObjects
http://blog.sina.com.cn/s/blog_7dc67d520100t2fb.html C++中queue等的使用方法
http://www.cnblogs.com/ZXYloveFR/p/3738155.html 一家人的周末餐与多线程----起步
问题:如何利用多线程实现UDP多服务器端的数据的融合,并保证周期为100ms以内。
方案一:(由一朋友提供)
方案二:
/************************************************************************/
/*
程序思路:先考虑一次传输过程,利用事件内核,来同步子线程与主线程,
利用临界区来实现锁的机制。
在利用事件时,我们利用自动复位事件实现,SetEvent来激活WaitForMultipleObjects,
当两个线程都执行完,程序执行到下一步,进入临界区,这里必须用锁,不然资源就会
发生冲突。
在临界区里面,主要是obs等一些变量的清零,还有数据的求并集,以及发送操作。
在利用UDP发送操作时,无谓的初始化可以省略,不要多搞。
*/
/************************************************************************/
最后,利用方案二实现。
遇到的问题:
到目前为止,我们都是等待其来临,自己去触发事件。但现实中有一难点无法处理,8线雷达,其每次都发送四层数据的信息
,需要两帧数据才可以发送数据。也就是说,八线雷达其数据周期为160ms,工作频率为12.5hz,我在想,假如我提高其频率,
将两帧数据放在八线雷达本身的客户端去处理,返回给我的还是一样的频率,这个可能会好点。提高到25hz即可。两帧数据位一周期,理论上应该可以解决这个问题。
也就是说,数据同步问题,还需要斟酌的去实现。
下面贴出代码:
.h文件 :
1: #ifndef NORMALNODE
2: #define NORMALNODE
3: #include <iostream>
4: #include <sstream>
5: #include <queue>
6: #include <Windows.h>
7: //socket头文件
8: #include "winsock.h"
9: //socket库的lib
10: #pragma comment(lib,"ws2_32.lib")
11: using namespace std;
12:
13: typedef unsigned short int uint;
14: typedef unsigned char uchar;
15: #define MAXSIZE 4000 // scan data模式 获得的最多点的个数
16:
17: const UINT16 Port1 = 8060;
18: const UINT16 Port2 = 8080;
19:
20: DWORD WINAPI Child0Func(LPVOID);
21: DWORD WINAPI Child1Func(LPVOID);
22:
23: char szbuffer[2][2000] = {0};//缓冲区用于存放字节流数据
24:
25: const int startoffset = 4;
26: const int PointLength = 6;
27:
28: CRITICAL_SECTION g_csThreadCode;
29:
30: typedef struct Point //点转换为矩阵的x与y坐标。
31: {
32: uint x;
33: uint y;
34: uchar value;
35: uchar U;
36: } Point;
37:
38: typedef struct Matrix //稀疏矩阵数据结构
39: {
40: int Num;
41: Point point[MAXSIZE];
42:
43: } Matrix;
44:
45: UINT16 count1 = 0;
46: Matrix matrix1;
47: Matrix matrix2;
48: #endif
<style type="text/css"> .csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, "Courier New", courier, monospace; background-color: #ffffff; /*white-space: pre;*/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em; } .csharpcode .lnum { color: #606060; }</style>
.cpp 文件:
1: // ThreadDemo6.cpp : 定义控制台应用程序的入口点。
2: //
3: #include "stdafx.h"
4: #include "Demo.h"
5: int _tmain(int argc, _TCHAR* argv[])
6: {
7: //初始化socket库
8: WSADATA wsa = {0}; //WinSockApi 取WSA+DATA组成套接字结构体
9: WSAStartup(MAKEWORD(2,2),&wsa);
10:
11: HANDLE hChild[4];
12: HANDLE hEvent[4];
13: DWORD threadId[4];
14: int obs1 = 0;
15: int obs2 = 0;
16: bool bDone = false;
17:
18: DWORD dwStart = GetTickCount();
19: InitializeCriticalSection(&g_csThreadCode);
20: //CreateEvent创建一个事件的时候,最后一个字符串是该事件的名字,
21: //这样就可以在其余的地方通过这个名字来找到相应的事件了,等于是一个标识的作用
22:
23: //第二个参数为true,所以为手动置位 。ResetEvent,使事件处于未触发状态
24: //一般情况下,当其处于触发状态,也就是SetEvent时,其他人可以更改
25: //第二个参数为false,表示自动置位,也就是不用ResetEvent。
26: //创建事件
27: hEvent[0] = CreateEventW(NULL,FALSE,FALSE,_T("ChildEvent0"));
28: hEvent[1] = CreateEventW(NULL,FALSE,FALSE,_T("ChildEvent1"));
29:
30: hChild[0] = CreateThread(NULL,0,Child0Func,0,0,&threadId[0]);//ID号与句柄
31: hChild[1] = CreateThread(NULL,0,Child1Func,0,0,&threadId[1]);
32:
33: /************************************************************************/
34: /*UDP部分 */
35: /************************************************************************/
36: SOCKET sClient;
37: int iLen; //服务器地址长度
38: int iSend; //接收数据的缓冲
39: struct sockaddr_in ser; //服务器端地址
40: //建立服务器端地址
41: ser.sin_family=AF_INET;
42: ser.sin_port=htons(8060);
43: ser.sin_addr.s_addr=inet_addr("127.0.0.1"); // 本机IP地址,测试用
44: //ser.sin_addr.s_addr = inet_addr("192.168.1.3"); //决策机IP地址
45:
46: //建立客户端数据报套接口
47: sClient=socket(AF_INET,SOCK_DGRAM,IPPROTO_UDP);
48:
49: if(sClient==INVALID_SOCKET)
50: {
51: printf("socket()Failed:%d\n",WSAGetLastError());
52: return 0;
53: }
54: iLen=sizeof(ser);
55: /********************************以上是UDP发送部分程序*****************************/
56:
57:
58: while(!bDone)
59: {
60: //下面这个方法有两种状态,一个是一个个去响应事件,一个是总的去响应事件。
61: DWORD dwStatus = WaitForMultipleObjects(2,hEvent,TRUE,INFINITE);//infinite,不等待,setEvent可以使其返回为0
62: if ((dwStatus >= WAIT_OBJECT_0)&&(dwStatus <= WAIT_OBJECT_0 + 1 ) )
63: {
64: DWORD dwStart = GetTickCount();
65: EnterCriticalSection(&g_csThreadCode);//进入关键段 临界区
66: //数据处理
67: UINT8 str1[2000] = {0};
68: UINT8 str2[2000] = {0};
69: //开辟两个无符号类型,这里是加了锁机制处理,string 默认并不是无符号类型
70: for (int i = 0; i < 2000; ++i)
71: {
72: str1[i] = szbuffer[0][i];
73: str2[i] = szbuffer[1][i];
74: }
75: matrix1.Num = str1[3]*16*16*16 + str1[2]*16*16 + str1[1]*16 + str1[0];
76: matrix2.Num = str2[3]*16*16*16 + str2[2]*16*16 + str2[1]*16 + str2[0];
77: for (int i = 0; i < matrix1.Num; ++i)
78: {
79: matrix1.point[obs1].x = str1[startoffset + 1 + i*PointLength]*16 + str1[startoffset + 0 + i*PointLength];
80: matrix1.point[obs1].y = str1[startoffset + 3 + i*PointLength]*16 + str1[startoffset + 2 + i*PointLength];
81: matrix1.point[obs1].value = str1[startoffset + 4 + i*PointLength];
82: matrix1.point[obs1].U = str1[startoffset + 5 + i*PointLength];
83: obs1++; //注意清零
84: }
85: for (int i = 0; i < matrix2.Num; ++i)
86: {
87: matrix2.point[obs2].x = str1[startoffset + 1 + i*PointLength]*16 + str1[startoffset + 0 + i*PointLength];
88: matrix2.point[obs2].y = str1[startoffset + 3 + i*PointLength]*16 + str1[startoffset + 2 + i*PointLength];
89: matrix2.point[obs2].value = str1[startoffset + 4 + i*PointLength];
90: matrix2.point[obs2].U = str1[startoffset + 5 + i*PointLength];
91: obs2++; //注意清零
92: }
93: obs1 = 0;
94: obs2 = 0;
95: Point poi;
96: //数据求并集然后发送
97: for (int i = 0; i < matrix1.Num; ++i)
98: {
99: poi = matrix1.point[i]; //四线雷达数据集
100: for (int j = 0; j < matrix2.Num; ++j)
101: {
102: if ((poi.x == matrix2.point[j].x) && (poi.y == matrix2.point[j].y))
103: {
104: matrix2.point[j] = matrix2.point[j+1];//大的替换小的
105: matrix2.Num--;
106: break;
107: }
108: }
109: }
110:
111: for (int i = 0; i < matrix2.Num; ++i)
112: {
113: matrix1.point[matrix1.Num + i] = matrix2.point[i];
114: }
115: matrix1.Num = matrix1.Num + matrix2.Num;
116:
117: uint len = matrix1.Num*sizeof(Point) + 4;
118: char buffer[10000];
119: memcpy(buffer,(char*)&matrix1,len);
120: iSend=sendto(sClient,buffer,len-1,0,(struct sockaddr*)&ser,iLen);
121: cout << "*************Total time:" << GetTickCount() - dwStart << endl;
122: LeaveCriticalSection(&g_csThreadCode);//离开关键段
123: }
124: }
125:
126:
127: for (int j = 0; j < 4; ++j)
128: {
129: CloseHandle(hEvent[j]);
130: CloseHandle(hChild[j]);
131: }
132: DeleteCriticalSection(&g_csThreadCode);
133: cout << "*************Total time:" << GetTickCount() - dwStart << endl;
134: return 0;
135: }
136:
137:
138: //子线程可以将主线程创建的Event激活
139: DWORD WINAPI Child0Func(LPVOID p)
140: {
141: HANDLE hEvent;
142: hEvent = OpenEventW(EVENT_ALL_ACCESS,FALSE,_T("ChildEvent0"));
143: SOCKET socksvr = socket(AF_INET,SOCK_DGRAM,IPPROTO_UDP);
144: if (INVALID_SOCKET == socksvr)
145: {
146: return 0;
147: }
148: struct sockaddr_in svraddr = {0};
149: svraddr.sin_family = AF_INET;
150: svraddr.sin_port = htons(5070);
151: svraddr.sin_addr.S_un.S_addr = htonl(INADDR_ANY);
152: if ( bind(socksvr,(struct sockaddr*)&svraddr,sizeof(svraddr)) == SOCKET_ERROR)//地址与套接字绑定
153: {
154: cout << "套接字绑定错误" << endl;
155: return 0;
156: }
157: struct sockaddr_in clientaddr = {0};
158: int nLen = sizeof(clientaddr);
159: while (true)
160: {
161: recvfrom(socksvr,(char*)szbuffer[0],2000,0,(struct sockaddr*)&clientaddr,&nLen);//构造ip地址
162: // cout << "flag1: "<<count1++ <<endl;
163: SetEvent(hEvent); //将事件置为有信号状态,WaitForObject返回为WAIT_OBJECT_0
164: }
165: }
166:
167: //子线程可以将主线程创建的Event激活
168: DWORD WINAPI Child1Func(LPVOID p)
169: {
170: HANDLE hEvent;
171: hEvent = OpenEventW(EVENT_ALL_ACCESS,FALSE,_T("ChildEvent1"));
172: SOCKET socksvr = socket(AF_INET,SOCK_DGRAM,IPPROTO_UDP);
173: if (INVALID_SOCKET == socksvr)
174: {
175: return 0;
176: }
177: struct sockaddr_in svraddr = {0};
178: svraddr.sin_family = AF_INET;
179: svraddr.sin_port = htons(5080);
180: svraddr.sin_addr.S_un.S_addr = htonl(INADDR_ANY);
181: if ( bind(socksvr,(struct sockaddr*)&svraddr,sizeof(svraddr)) == SOCKET_ERROR)//地址与套接字绑定
182: {
183: cout << "套接字绑定错误" << endl;
184: return 0;
185: }
186: struct sockaddr_in clientaddr = {0};
187: int nLen = sizeof(clientaddr);
188: while (true)
189: {
190: recvfrom(socksvr,(char*)szbuffer[1],2000,0,(struct sockaddr*)&clientaddr,&nLen);//构造ip地址
191: // cout << "flag2: "<<count1++ <<endl;
192: SetEvent(hEvent); //将事件置为有信号状态,WaitForObject返回为WAIT_OBJECT_0
193: }
194: }