`
dogasshole
  • 浏览: 840310 次
文章分类
社区版块
存档分类
最新评论

VC深入详解之第十五章多线程编程

 
阅读更多
真正完成代码执行的是线程,而进程知识线程的容器,或者说是线程的执行环境。
线程有两部分组成:线程的内核对象和线程栈


#include<windows.h>
#include<iostream>
using namespace std;


DWORD WINAPI Func1Proc(LPVOID lpParameter);
DWORD WINAPI Func2Proc(LPVOID lpParameter);


int index = 0;
int tickets = 100;
HANDLE hMutex;


void main()
{
HANDLE hThread1;
HANDLE hThread2;


hThread1 = CreateThread(NULL, 0, Func1Proc, NULL, 0, NULL);
hThread2 = CreateThread(NULL, 0, Func2Proc, NULL, 0, NULL);

CloseHandle(hThread1);
CloseHandle(hThread2);


hMutex = CreateMutex(NULL, TRUE, NULL);
//WaitForSingleObject(hMutex,INFINITE);
ReleaseMutex(hMutex);
//ReleaseMutex(hMutex);
Sleep( 4000);
}


DWORD WINAPI Func1Proc( LPVOID lpParameter)
{
while(TRUE)
{
// Sleep(1);
WaitForSingleObject( hMutex, INFINITE);
if(tickets>0)
{
Sleep(1);
cout << "thread1 sell ticket : " << tickets-- << endl;
}
else
{
break;
}
ReleaseMutex(hMutex);
}
return 0;
}




DWORD WINAPI Func2Proc( LPVOID lpParameter)
{
while(TRUE)
{
//Sleep(1);
WaitForSingleObject( hMutex, INFINITE);
if(tickets>0)
{
Sleep(1);
cout << "thread2 sell ticket : " << tickets-- << endl;
}
else
{
break;
}
ReleaseMutex(hMutex);

}
return 0;
}


创建线程参数说明:
HANDLE CreateThread(
LPSECURITY_ATTRIBUTES lpThreadAttributes,//设置为NULL,则指定默认的安全属性,如果希望所有的子进程能够继承该线程对象的句柄,则需要设定该结构体,并将结构体中bInheritHandle成员初始化为TRUE
DWORD dwStackSize,//设置线栈初始化大小,如果值为0,那么默认将使用与调用该函数的饿线程相同的栈空间大小
LPTHREAD_START_ROUTINE lpStartAddress,//新线程的其实地址,一般为一个函数名
LPVOID lpParameter,//向新线程函数传递的参数
DWORD dwCreateionFlags,//创建标志:为CREATE_SUSPENDED就处于暂停状态,直至调用ResumeThread函数。如果值为0,就立即运行
LPDWORD lpThreadId//输出参数,接收线程的ID,可以为NULL
);


创建互斥对象的参数说明:
HANDLE CreateMutex(
LPSECURITY_ATTRIBUTES lpMutexAttributes,//执行互斥对象的安全属性,可以为NULL
BOOL bInitialOwner,//指定互斥对象初始的拥有者
LPCTSTR lpName//指定互斥对象的名称,如果值为NULL,则创建的是一个匿名的互斥对象
);


请求和释放互斥对象:
DWORD WaitForSingleObject( HANDLE hHandle, DWORD dwMilliseconds);
dwMilliseconds指定等待时间的间隔,以毫秒为单位。如果将此参数设置为INFINITE,则该函数会永远等待,知道等待的对象处于有信号状态才会返回。
BOOL ReleaseMutex( HANDLE hMutex);


对于互斥对象来说,它是唯一与线程相关的内核对象。当主线程拥有互斥对象时,操作系统会将互斥对象的线程ID设置为主线程的ID。当其他线程中调用ReleaseMutex函数释放互斥对象的所有权时,操作系统会判断该线程的线程ID与互斥对象内部所维护的线程ID是否相等,只有相等才能完成释放操作。也就是说,对互斥对象来说,谁拥有谁释放。
同样,当调用WaitForSingleObject函数时,操作系统也会去判断当前请求互斥对象的线程的ID是否与互斥对象当前拥有者的线程ID相等,如果相等,即使该互斥对象处于未通知状态,调用线程任然能够获得其所有权,然后WaitForSingleObject函数返回。对于同一个线程多次拥有的互斥对象来说,该互斥对象内部的计数器记录了该线程拥有的次数,也就是说:当一个线程拥有互斥对象以后,再次调用WaitForSingleObject函数,互斥对象的计数器就增加1,当调用ReleaseMutex函数释放互斥对象的所有权时,互斥对象的计数器减1,如果该计数器的值不为0,那么该互斥对象任然处于未通知状态。




保证应用程序只有一个实例运行:
要实现只有一个实例运行的功能,可以通过命名的互斥对象来实现。在调用CreateMutex函数创建一个命名的互斥对象后,如果其返回值是一个有效的就句柄,那么可以接着调用GetLastError函数,如果该函数返回的是ERROR_ALREADY_EXISTS,这就表明先前已经创建了这个命名的互斥对象,因此就可以知道先前已经有该应用程序的一个实例在运行了。当然,如果GetLastError函数返回的不是ERROR_ALREADY_EXISTS,就说明这个互斥对象是新创建的,从而也就知道当前启动的这个进程是应用程序第一个实例。




在MFC中提供了一个完成版本协商的函数:
BOOL AfxSocketInit( WSADATA * lpwsData = NULL );//应该在应用程序类重载的InitInstance函数中调用AfxSocketInit函数。


IP控件对应的MFC类时:CIPAddressCtrl。这个类有一个GetAddress成员函数,该函数将返回IP地址控件中非空白字段的数值。




定义一个线程用以接收消息:
DWORD WINAPI CChatDlg::RecvProc(LPVOID lpParameter)
{
SOCKET sock = ((RECVPARAM*)lpParameter)->sock;
HWND hwnd = ((RECVPARAM*)lpParameter)->hwnd;
delete lpParameter;


SOCKADDR_IN addrFrom;
int len = sizeof(SOCKADDR);


char recvBuf[200];
char tempBuf[300];
int retval;
while(1)
{
retval = recvfrom(sock, recvBuf, 200, 0, (SOCKADDR*)&addrFrom, &len);
if(SOCKET_ERROR == retval)
{
break;
}
sprintf(tempBuf, "%s say: %s" , inet_ntoa(addrFrom.sin_addr), recvBuf);
::PostMessage(hwnd, WM_RECVDATA, 0, (LPARAM)tempBuf);


}
return 0;
}


网络编程补充:
在服务器端,需要用到SOCKADDR_IN结构的一个变量,供bind只用,与此同时,还需要定义一个SOCKADDR_IN变量,用于recvfrom接收时保存客户端地址。
在客户端:
需要定义一个SOCKADDR_IN变量,供sendto发送时指定地址。
分享到:
评论

相关推荐

    Visual C++网络编程案例_part2.rar

    第1篇介绍了Visual C++网络开发基础知识,包括Visual C++网络编程概述、Socket套接字编程和多线程与异步套接字编程。第2篇介绍了7大类网络开发典型应用案例的实现,包括FTP客户端实现之一、 FTP客户端实现之二、网页...

    Visual_C++精彩实例详解

    第15章 拨号上网实例 第16章 FTP协议编程 第17章 Telnet协议编程 第18章 Email协议编程 第19章 基于UDP协议的网段扫描器 第20章 具有异形窗口的网络电话 第21章 电影播放器 第22章 AVI视频制作编程 第23章 文字语音...

    Visual_C++精彩实例详解.part2.rar

    第15章 拨号上网实例 第16章 FTP协议编程 第17章 Telnet协议编程 第18章 Email协议编程 第19章 基于UDP协议的网段扫描器 第20章 具有异形窗口的网络电话 第21章 电影播放器 第22章 AVI视频制作编程 第23章 文字语音...

    Visual_C++精彩实例详解.part4.rar

    第15章 拨号上网实例 第16章 FTP协议编程 第17章 Telnet协议编程 第18章 Email协议编程 第19章 基于UDP协议的网段扫描器 第20章 具有异形窗口的网络电话 第21章 电影播放器 第22章 AVI视频制作编程 第23章 文字语音...

    Visual_C++精彩实例详解.part5.rar

    第15章 拨号上网实例 第16章 FTP协议编程 第17章 Telnet协议编程 第18章 Email协议编程 第19章 基于UDP协议的网段扫描器 第20章 具有异形窗口的网络电话 第21章 电影播放器 第22章 AVI视频制作编程 第23章 文字语音...

    Visual_C++精彩实例详解.part3.rar

    第15章 拨号上网实例 第16章 FTP协议编程 第17章 Telnet协议编程 第18章 Email协议编程 第19章 基于UDP协议的网段扫描器 第20章 具有异形窗口的网络电话 第21章 电影播放器 第22章 AVI视频制作编程 第23章 文字语音...

    vc源代码合集2244.rar

    2012-06-11 22:33 1,411,072 第15章 仿QQ游戏大厅.doc 2012-06-11 22:21 13,468,514 纯C论坛的资料.rar 2012-06-11 22:27 248,320 编写高效率的testbench.doc 2012-06-11 22:34 7,705,389 计算机网络高级软件编程...

    windows驱动开发技术详解-part2

     8.5.2 内核模式下开启多线程  8.5.3 内核模式下的事件对象  8.5.4 驱动程序与应用程序交互事件对象  8.5.5 驱动程序与驱动程序交互事件对象  8.5.6 内核模式下的信号灯  8.5.7 内核模式下的互斥体  ...

    Windows驱动开发技术详解的光盘-part1

     8.5.2 内核模式下开启多线程  8.5.3 内核模式下的事件对象  8.5.4 驱动程序与应用程序交互事件对象  8.5.5 驱动程序与驱动程序交互事件对象  8.5.6 内核模式下的信号灯  8.5.7 内核模式下的互斥体  ...

    asp.net知识库

    深入剖析ASP.NET组件设计]一书第三章关于ASP.NET运行原理讲述的补白 asp.net 运行机制初探(httpModule加载) 利用反射来查看对象中的私有变量 关于反射中创建类型实例的两种方法 ASP.Net应用程序的多进程模型 NET委托...

Global site tag (gtag.js) - Google Analytics