多线程编程

来源:互联网 发布:梅西c罗数据对比 编辑:程序博客网 时间:2024/06/05 09:31

最近看网络编程的知识,涉及到多线程编程,顺便把以前的知识复习一下...也快忘记了。

什么是进程:

进程是一个应用程序的实例,也可以看成是一个程序运行的环境。进程包括两个部分:一、内核对象,该对象由系统维护,包含了进程的相关信息;二、地址空间,包含了可执行模块、DLL链接库模块代码和数据。每个进程启动时,操作系统都会为之分配4GB的虚拟地址空间。

什么是线程:

线程就是可执行程序,每个进程最少包含一个线程,称为主线程。线程也包括两部分:一、内核结构,包含了线程的相关信息;二、线程栈,维护线程运行时所需要的参数和局部变量。线程所需要的资源都由所属的进程提供。

什么是虚拟内存:

虚拟内存就是一磁盘的单元,是由磁盘分配出来把它当成内存使用。当我们在内存为1G的电脑上运行1G+200M的程序时,此时虚拟内存就起到了作用。以前记过现在不太记得了,虚拟内存大概的工作原理是这样的,当在运行1G的程序时,并不真正要用到1G的内存,此时它可能只需要800M的内存,所以我们需要把剩余的那个部分存储起来,当要运行的时候在提起出来,而剩下的存就可以去运行200M的内存了。具体虚拟内存是如何与实际内存联系起来的,下面来解释。

Windows内存存储管理方式:

Windows管理内存的方式有三种(记得是看一道面试题看到的,当时找了一下资料,有不对的还望指正)。页式管理:将虚拟内存划分成若干个大小相同的页面,让后通过页表与实际的内存建立联系;这样做的好处是有效的增大了可以使用的内存,而起可以很方便的管理内存,进程的程序段和数据在内存中不用连续存放,不好的是容易造成浪费且需要硬件上的支持。

段式管理:将内存按内容或函数划分成不等的段,相应的有代码段、函数段等;这样做的好处是可以节约内存,但不够方便。

段页式管理:结合了页式管理与段式管理,每个段就形成一个页,再建立页表与实际的内存关联起来你。

4GB的虚拟内存:

正如上面所说,4GB的内存虚拟的,操作系统不可能为每个进程分配这么大的实际内存,实际上分配的内存远小于4GB。这4GB包含了内核区和用户区。正因为每次启动进程都要为其分配4GB的内存,所以一般不使用多进程,而使用多线程。

线程同步:

开始老是被名字误解,以为线程同步就是多个线程一起运行实际上不是的,线程同步的意思是多个线程协调同时完成某个工作。线程同步的方法有很多,常见的有事件、互斥对象、临界区等。其中,使用临界区的效率比较好。事关事件和互斥对象都是内核对象,使用起来时速度比较慢,但如果是在多进程间实现线程同步,就要使用事件和内核对象了。

进程间通信:

   进程间通信可以以剪贴板、油槽、匿名管道、命名管道、套接字等等。其中油槽只能发送的数据不能超过400KB,匿名管道只能在本地机器上通信,命名管道和油槽可以在网络间通信。

下面看一下使用临界区的多线程编程和使用命名管道的多进程的例子:

临界区:#include<stdio.h>#include <Windows.h>DWORD WINAPI ThreadProc1(LPVOID lpParameter);DWORD WINAPI ThreadProc2(LPVOID lpParameter);DWORD WINAPI ThreadProc3(LPVOID lpParameter);CRITICAL_SECTION se;int a=0;void main(){HANDLE hThread1;HANDLE hThread2;HANDLE hThread3;hThread1=CreateThread(NULL,0,ThreadProc1,NULL,0,0);//不一定是线程一先启动运行hThread2=CreateThread(NULL,0,ThreadProc2,NULL,0,0);hThread3=CreateThread(NULL,0,ThreadProc3,NULL,0,0);::InitializeCriticalSection(&se);::CloseHandle(hThread1);::CloseHandle(hThread2);::CloseHandle(hThread3);    Sleep(5000);}//操作系统会公平对待所创建的线程,也就是说那个线程先启动时未知的。DWORD WINAPI ThreadProc1(LPVOID lpParameter){while (a<100){Sleep(1000);::EnterCriticalSection(&se);printf("The Thread1:%d\n",a);a++;::LeaveCriticalSection(&se);}return 0;}DWORD WINAPI ThreadProc2(LPVOID lpParameter){while (a<100){Sleep(1000);::EnterCriticalSection(&se);printf("The Thread2:%d\n",a);a++;::LeaveCriticalSection(&se);}return 0;}DWORD WINAPI ThreadProc3(LPVOID lpParameter){while (a<100){Sleep(1000);::EnterCriticalSection(&se);printf("The Thread3:%d\n",a);a++;::LeaveCriticalSection(&se);}return 0;}服务器:#include <windows.h>#include <stdio.h>int main(){HANDLE HName;OVERLAPPED ol;ZeroMemory(&ol,sizeof(OVERLAPPED));//必须初始化DWORD wd;HName=CreateNamedPipe("\\\\.\\pipe\\skypipe",PIPE_ACCESS_DUPLEX,0,1,1024,1024,0,NULL);  //创建命名管道if (HName== INVALID_HANDLE_VALUE){printf("创建命名管道失败");return 0;}char senBuf[6]="hello";ConnectNamedPipe(HName,&ol);//等待连接    WriteFile(HName,senBuf,6,&wd,&ol);//写入数据Sleep(5000);return 0;}客户端:#include <windows.h>#include <stdio.h>int main(){if(!WaitNamedPipe("\\\\.\\pipe\\skypipe",NMPWAIT_WAIT_FOREVER)) //连接命名管道{printf("连接命名管道失败");return 0;}HANDLE HFile;DWORD dw;HFile=CreateFile("\\\\.\\pipe\\skypipe",GENERIC_READ,FILE_SHARE_READ,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL);//打开管道if (HFile==INVALID_HANDLE_VALUE){printf("打开命名管道失败");return 0;}char recBuf[6];    ReadFile(HFile,recBuf,6,&dw,NULL);//读取数据recBuf[6]='\0';printf(recBuf);return 0;}


 

原创粉丝点击