真正完成代码执行的是线程,而进程知识线程的容器,或者说是线程的执行环境。
线程有两部分组成:线程的内核对象和线程栈
#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发送时指定地址。
分享到:
相关推荐
第1篇介绍了Visual C++网络开发基础知识,包括Visual C++网络编程概述、Socket套接字编程和多线程与异步套接字编程。第2篇介绍了7大类网络开发典型应用案例的实现,包括FTP客户端实现之一、 FTP客户端实现之二、网页...
第15章 拨号上网实例 第16章 FTP协议编程 第17章 Telnet协议编程 第18章 Email协议编程 第19章 基于UDP协议的网段扫描器 第20章 具有异形窗口的网络电话 第21章 电影播放器 第22章 AVI视频制作编程 第23章 文字语音...
第15章 拨号上网实例 第16章 FTP协议编程 第17章 Telnet协议编程 第18章 Email协议编程 第19章 基于UDP协议的网段扫描器 第20章 具有异形窗口的网络电话 第21章 电影播放器 第22章 AVI视频制作编程 第23章 文字语音...
第15章 拨号上网实例 第16章 FTP协议编程 第17章 Telnet协议编程 第18章 Email协议编程 第19章 基于UDP协议的网段扫描器 第20章 具有异形窗口的网络电话 第21章 电影播放器 第22章 AVI视频制作编程 第23章 文字语音...
第15章 拨号上网实例 第16章 FTP协议编程 第17章 Telnet协议编程 第18章 Email协议编程 第19章 基于UDP协议的网段扫描器 第20章 具有异形窗口的网络电话 第21章 电影播放器 第22章 AVI视频制作编程 第23章 文字语音...
第15章 拨号上网实例 第16章 FTP协议编程 第17章 Telnet协议编程 第18章 Email协议编程 第19章 基于UDP协议的网段扫描器 第20章 具有异形窗口的网络电话 第21章 电影播放器 第22章 AVI视频制作编程 第23章 文字语音...
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 计算机网络高级软件编程...
8.5.2 内核模式下开启多线程 8.5.3 内核模式下的事件对象 8.5.4 驱动程序与应用程序交互事件对象 8.5.5 驱动程序与驱动程序交互事件对象 8.5.6 内核模式下的信号灯 8.5.7 内核模式下的互斥体 ...
8.5.2 内核模式下开启多线程 8.5.3 内核模式下的事件对象 8.5.4 驱动程序与应用程序交互事件对象 8.5.5 驱动程序与驱动程序交互事件对象 8.5.6 内核模式下的信号灯 8.5.7 内核模式下的互斥体 ...
深入剖析ASP.NET组件设计]一书第三章关于ASP.NET运行原理讲述的补白 asp.net 运行机制初探(httpModule加载) 利用反射来查看对象中的私有变量 关于反射中创建类型实例的两种方法 ASP.Net应用程序的多进程模型 NET委托...