孙鑫多线程笔记

上传人:ji****72 文档编号:37696998 上传时间:2018-04-21 格式:DOC 页数:20 大小:236KB
返回 下载 相关 举报
孙鑫多线程笔记_第1页
第1页 / 共20页
孙鑫多线程笔记_第2页
第2页 / 共20页
孙鑫多线程笔记_第3页
第3页 / 共20页
孙鑫多线程笔记_第4页
第4页 / 共20页
孙鑫多线程笔记_第5页
第5页 / 共20页
点击查看更多>>
资源描述

《孙鑫多线程笔记》由会员分享,可在线阅读,更多相关《孙鑫多线程笔记(20页珍藏版)》请在金锄头文库上搜索。

1、孙鑫 VC 学习笔记:多线程编程= =程序程序DWORD WINAPI Fun1Proc(LPVOID lpParameter);/声明线程入口函数void main()/创建新线程HANDLE hThread1;hThread1 = CreateThread( NULL,/使用缺省的安全性0,/初始提交的栈的大小Fun1Proc,/线程入口函数NULL,/传递为线程的参数0,/附加标记 0 表示线程创建后立即运行NULL);/线程 ID/关闭线程句柄,但不会终止新建的线程CloseHandle(hThread1);cout0)cout0)cout 孙鑫给的结果是两个线程轮流执行操作,输出结果

2、如下,他的机子是单核的thread1 sale the ticket id is:50thread2 sale the ticket id is:49。我在两个线程的 if 语句中加入 Sleep(1000);,这样能清楚的看到双核下线程 的运行状况thread1 sale the ticket id is:thread2 sale the ticket id is:5049 【双核下】 【问题:同时运行,但是输出都是最后一起输出】。= =说明说明= =问题:上述例 1,有可能会遇到如下一种情况:【单核】当 ticket 数量运行到 1 时,线程 1 正在运行,此时线程 1 运行到输出语句时,

3、 它的时间片已经结束,则线程 1 对 ticket id 的减减动作没有完成,此时线程 2 开始 执行,发现数量是 1,则执行减减动作,使得数量为 0,返回,线程 1 继续执行, 此时票的数量已经是 0 了,线程 1 继续执行输出语句,对票的数量执行减减,则数 量变为-1,这是不允许的。这是由于抢占全局的资源所引起的。解决这个问题的办法是实现线程间的“同步”,即一个线程在对一个全局的资源 进行操作的过程中,是不允许其他线程对全局的资源进行访问,直到该线程对资源 操作完毕后。涉及概念:互斥对象 互斥对象(mutex)属于内核对象,它能够确保线程拥有对单个资源的互斥访问权。互斥对象包含一个使用数量

4、,一个线程使用数量,一个线程 ID 和一个计数器一个计数器。ID 用于标识系统中的哪个线程当前拥有互斥对象,计数器用于指明该线程 拥有互斥对象的次数。 涉及到三个函数:1.CreateMutex:创建互斥对象,返回互斥对象的句柄HANDLE CreateMutex(LPSECURITY_ATTRIBUTES lpMutexAttributes,/ BOOL bInitialOwner, / flag for initial ownership,LPCTSTR lpName / pointer to mutex-object name);参 数 1指向 SECURITY_ATTRIBUTES 结

5、构体的指针。可以传递 NULL,让其使用默 认的安全性。参 数 2指示互斥对象的初始拥有者。 如果该值是真,调用者创建互斥对象,调用的线 程获得互斥对象的所有权。 否则,调用线程捕获的互斥对象的所有权。(就是 说,如果该参数为真,则调用该函数的线程拥有互斥对象的所有权。否则,不拥 有所有权,当前互斥对象处于空闲状态,其他线程可以占用)参 数 3互斥对象名称。传递 NULL 创建的就是没有名字的互斥对象,即匿名的互斥对 象。返 回创建成功之后 ,返回一个互斥对象句柄。如果一个命名的互斥对象在本函数调 用之前已经存在,则返回已经存在的对象句柄。然后可以调用 GetLastError 检 查其返回值

6、是否为 ERROR_ALREADY_EXISTS,TRUE 则表示命名互斥对象 已经存在,否则表示互斥对象是新创建的。当前没有线程拥有互斥对象,操作系统会将互斥对象设置为已通知状态(有信 号状态)2.WaitForSingleObject:等待互斥对象的使用权,如果第二个参数设置为 INFINITE,则表示会持续等待下去,直到拥有所有权,才有权执行该函数下面的语 句。一旦拥有了所有权,则会将互斥对象的的线程 ID 设置为当前使用的线程 ID 值。3.ReleaseMutex:将互斥对象所有权进行释放,交还给系统。 理解:可以将互斥对象想象成一把钥匙,CreateMutex 创建了这把钥匙,Wa

7、itForSingleObject 等待这把钥匙去访问一个公共的资源,比如一个房间, 如果拥有了钥匙,则这个房间的所有权就属于这个进程了,别人是进不去这个 房间的,直到进程将这个房间的钥匙归还掉,即 ReleaseMutex。 调用的形式 【思路】:互斥条件实现线程同步/在主线程中.HANDLE hMutex = CreateMutex(NULL, FALSE, NULL);./其他线程中.WaitForSingleObject(hMutex, INFINITE);/受保护的代码.ReleaseMutex(hMutex);解决方法:增加互斥条件,实现线程之间的同步 代码如下例 2= =实例 2

8、(车票销售) 增加互斥条件 #include “iostream“using namespace std;#include “windows.h“DWORD WINAPI ThreadProc1(LPVOID lpParameter); DWORD WINAPI ThreadProc2(LPVOID lpParameter);int ticket=50;HANDLE hMutex;void main()HANDLE handle1=CreateThread(NULL,0,ThreadProc1,NULL,0,NULL);HANDLE handle2=CreateThread(NULL,0,Th

9、readProc2,NULL,0,NULL);CloseHandle(handle1);CloseHandle(handle2);/说明:为了使得主线程在退出之前保证副进程的执行完成,有些实现方法是采用 恒真的空循环,单此种方法主线程会占用 cpu 的运行时间,如果采用 Sleep,则主 线程完全不占用 cpu 的任何运行时间hMutex=CreateMutex(NULL,FALSE,NULL); /第二个参数为 FALSE,将互斥对象声明为 空闲状态Sleep(4000); DWORD WINAPI ThreadProc1(LPVOID lpParameter)/说明:在线程的时间片内持续运

10、行while(TRUE)WaitForSingleObject(hMutex,INFINITE); /第二个参数为 INFINITE 表示一直等 待,直到拥有互斥对象if(ticket0)Sleep(1);cout0) Sleep(1);couthWnd=m_hWnd;pRecvParam-sock=m_socket;说明:1.接收部分应该一直处于响应状态,如果和发送部分放在同一段代码中, 势必会阻塞掉发送功能的实现,所以考虑将接收放在单独的线程中,使它 在一个 while 循环中,始终处于响应状态2.因为需要传递两个参数进去,一个是 recvfrom 需要用的套接字,另一 个是当收到数据后需

11、要将数据显示在窗口中的对应文本框控件上,所以需 要传递当前窗口的句柄,但 CreateThread 方法只能传递一个参数,即第 四个参数,这时候就想到了采用结构体的方式传递。HANDLE hThread=CreateThread(NULL,0,RecvProc,(LPVOID)pRecvParam, 0,NULL);/第二个参数是 0 是为了保持和主线程保持相同的空间CloseHandle(hThread);7.创建线程入口函数 RecvProc:可模仿 ThreadProc 的创建方式(在 MSDN 中有原型),但遇到一个问题, 将该函数申明为 CChatDlg 的成员函数嘛?答案不是的,因

12、为如果是成员函 数的话,那它属于某个具体的对象,那么在调用它的时候势必要让程序创建 一个对象,但该对象的构造函数有参数的话,系统就不知所措了,所以可以 将函数创建为全局函数,即不属于类,但这失去了类的封装性,最好的方法 是将该方法声明为静态方法,它不属于任何一个对象。在 CChatDlg 类的头文件中添加:static DWORD WINAPI RecvProc(LPVOID lpParameter);在 cpp 文件中添加:DWORD WINAPI CChatDlg:RecvProc(LPVOID lpParameter)RECVPARAM* pRecvParam=(RECVPARAM*)l

13、pParameter;HWND hWnd=pRecvParam-hWnd;SOCKET sock=pRecvParam-sock;char recvBuf200;char resultBuf200;SOCKADDR_IN addrFrom; /这个时候是假想成服务器端int len=sizeof(SOCKADDR_IN);while(TRUE) /处于持续响应状态Int retVal=recvfrom(sock,recvBuf,200,0,(SOCKADDR*) /从客户端接收数据,并将客户端的地址结构体填充if(SOCKET_ERROR = retVal)AfxMessageBox(“接收数

14、据出错“);/因为本函数是静态函数,所以只能调用全局的消息了break;elsesprintf(resultBuf,“%s said:%s“,inet_ntoa(addFrom.sin_addr),recvBuf);/现在已经拿到客户端送过来的消息了,但因为自身是静态函数, 所以拿不到当前窗口对象中的控件的句柄,也就不能对其赋值了, 唯一办法就是用消息的形式将接收到的值抛出到窗口的消息队列 中,等待消息处理:PostMessage(hWnd,WM_RECVDATA,0,(LPARAM)resultBuf); return 0;8.自定义消息:定义自定义消息的宏:#define WM_RECVD

15、ATA WM_USER+1声明消息响应函数:因为有参数要传递,所以 wParam 和 lParam 都要写, 如果没有参数需要传递,可以不写afx_msg void OnRecvData(WPARAM wParam,LPARAM lParam);消息映射:(记得不加分号)ON_MESSAGE(WM_RECVDATA,OnRecvData)定义消息响应函数:void CChatDlg:OnRecvData(WPARAM wParam,LPARAM lParam)/注意将文本框的属性设置成多行,否则不会换行。CString recvData=(char*)lParam;CString temp; /文本框中现有的内容GetDlgItemText(IDC_EDIT_RECV,temp);temp+=

展开阅读全文
相关资源
相关搜索

当前位置:首页 > 行业资料 > 其它行业文档

电脑版 |金锄头文库版权所有
经营许可证:蜀ICP备13022795号 | 川公网安备 51140202000112号