文档章节

Windows 多进程通信API总结

东风125
 东风125
发布于 2015/09/07 13:23
字数 3418
阅读 927
收藏 2

在一个大型的应用系统中,往往需要多个进程相互协作,进程间通信(IPC,Inter Process Communication)就显得比较重要了。在Linux系统中,有很多种IPC机制,比如说,信号(signal)、管道(pipe)、消息队列(message queue)、信号量(semaphore)和共享内存(shared memory)、套接字(socket)等,其实Windows操作系统也支持这些东西。在IBM的Developerworks发现了一篇关于Windows与Linux 之间IPC机制API比较的文章,写得很不错,链接

http://www.ibm.com/developerworks/cn/linux/l-ipc2lin1.html

下面大部分内容是关于这些机制的API的实现。

创建进程

进程的创建可以调用CreateProcess函数,CreateProcess有三个重要的参数,运行进程的名称、指向STARTUPINFO结构的指针、指向PROCESS_INFORMATION结构的指针。其原型如下:

[cpp] view plaincopyprint?

  1. BOOL CreateProcess  

  2. (  

  3. LPCTSTRlpApplicationName,  

  4. LPTSTR lpCommandLine,  

  5. LPSECURITY_ATTRIBUTES lpProcessAttributes。  

  6. LPSECURITY_ATTRIBUTES lpThreadAttributes,  

  7. BOOL bInheritHandles,  

  8. DWORD dwCreationFlags,  

  9. LPVOID lpEnvironment,  

  10. LPCTSTR lpCurrentDirectory,  

  11. LPSTARTUPINFOlpStartupInfo,  

  12. LPPROCESS_INFORMATIONlpProcessInformation  

  13. );  


给个例子,如果启动时应用程序带有命令行参数,进程将输出命令行参数,并创建一个不带任何参数的子线程;如果不带有任何参数,则会输出一条提示消息。

[cpp] view plaincopyprint?

  1. #include <Windows.h>  

  2. #include <tchar.h>  

  3. #include <iostream>  

  4. using namespace std;  

  5. int _tmain(int argc, _TCHAR* argv[]){  

  6.     STARTUPINFO startup_info;  

  7.     PROCESS_INFORMATION process_info;  

  8.     if (argc>1)  

  9.     {  

  10.         cout<<"Argument"<<argv[1]<<endl;  

  11.         cout<<"开启子线程"<<endl;  

  12.         ZeroMemory(&process_info,sizeof(process_info));  

  13.         ZeroMemory(&startup_info,sizeof(startup_info));  

  14.         startup_info.cb=sizeof(startup_info);  

  15.         if (CreateProcess(argv[0],0,0,0,0,0,0,0,&startup_info,&process_info)==0)  

  16.         {  

  17.             cout<<"Error"<<endl;  

  18.         }  

  19.         WaitForSingleObject(process_info.hProcess,INFINITE);  

  20.     }  

  21.     else{  

  22.         cout<<"No arguments"<<endl;  

  23.     }  

  24.     getchar();  

  25. }  


再给个例子,利用CreateProcess开启一个新线程,启动IE浏览器,打开百度的主页,5s后再将其关闭。


[cpp] view plaincopyprint?

  1. #include <Windows.h>  

  2. #include <tchar.h>  

  3. #include <iostream>  

  4. using namespace std;  

  5. #define IE L"C:\\Program Files\\Internet Explorer\\iexplore.exe"    

  6. #define CMD L"open http://www.baidu.com/"    

  7. int _tmain(int argc, _TCHAR* argv[]){  

  8.     STARTUPINFO startup_info;  

  9.     GetStartupInfo(&startup_info);  

  10.     PROCESS_INFORMATION process_info;  

  11.     startup_info.dwFlags=STARTF_USESHOWWINDOW;  

  12.     startup_info.wShowWindow=SW_HIDE;  

  13.     if (!CreateProcess(IE,CMD,NULL, NULL, FALSE, CREATE_NO_WINDOW, NULL, NULL,&startup_info,&process_info))  

  14.     {  

  15.         cout<<"Create Process Error:"<<GetLastError()<<endl;  

  16.         return 0;  

  17.     }  

  18.     Sleep(5000);  

  19.     TerminateProcess(process_info.hProcess,0);  

  20.     return 0;  

  21. }  


被创建的句柄通过process_info.hProcess返回。如果传递参数给新的进程,第一个命令行参数必须重复应用程序名称,整个命令行会被传递给子进程。


传递参数给新进程。

[cpp] view plaincopyprint?

  1. #include <Windows.h>  

  2. #include <tchar.h>  

  3. #include <iostream>  

  4. using namespace std;  

  5. int _tmain(int argc, _TCHAR* argv[]){  

  6.     STARTUPINFO startup_info;  

  7.     PROCESS_INFORMATION process_info;  

  8.     if (argc==1)  

  9.     {  

  10.         cout<<"No arguments given starting child process"<<endl;  

  11.         wchar_t argument[256];  

  12.         wsprintf(argument,L"\"%s\" Hello",argv[0]);  

  13.         ZeroMemory(&process_info,sizeof(process_info));  

  14.         ZeroMemory(&startup_info,sizeof(startup_info));  

  15.         startup_info.cb=sizeof(startup_info);  

  16.         if (CreateProcess(argv[0],argument,0,0,0,0,0,0,&startup_info,&process_info)==0)  

  17.         {  

  18.             cout<<"Error "<<GetLastError()<<endl;  

  19.         }  

  20.         WaitForSingleObject(process_info.hProcess,INFINITE);  

  21.     }  

  22.     else{  

  23.         cout<<"Argument "<<argv[1]<<endl;  

  24.     }  

  25.     getchar();  

  26. }  




IPC

进程间可以共享内存,进程建立具有共享属性的内存区域后,另一个进程可以打开此内存区域,并将其映射到自己的地址空间。共享内存可以使用文件映射函数CreateFileMapping,创建共享内存区域的句柄,通过MapViewOfFile()把这个区域映射到进程,然后再连接到现有的共享内存区域,可以通过OpenFileMapping获得句柄。在进程使用完共享内存后,需要调用UnmapViewOfFile()取消映射,再调用CloseHandle()关闭相应的句柄,避免内存泄露。

给个例子,如果启动时应用程序不带任何参数,应用程序会创建一个子进程。父进程也将建立一个共享内存区域,并将一个字符串保存到共享内存。共享内存取名为sharedmemory,在Local\命名空间中创建,即该共享内存对该用户所有的全部进程可见。(进程的命名空间分为两种,全局命名空间以Global\标识符开头,本地命名空间以Local\开头)

[cpp] view plaincopyprint?

  1. #include <Windows.h>  

  2. #include <tchar.h>  

  3. #include <iostream>  

  4. using namespace std;  

  5. int _tmain(int argc, _TCHAR* argv[]){  

  6.     STARTUPINFO startup_info;  

  7.     PROCESS_INFORMATION process_info;  

  8.     HANDLE filehandle;  

  9.     TCHAR ID[]=TEXT("Local\\sharedmemory");  

  10.     char* memory;  

  11.     if (argc==1)  

  12.     {  

  13.         filehandle=CreateFileMapping(INVALID_HANDLE_VALUE,NULL,PAGE_READWRITE,0,1024,ID);  

  14.         memory=(char*)MapViewOfFile(filehandle,FILE_MAP_ALL_ACCESS,0,0,0);  

  15.         sprintf_s(memory,1024,"%s","Data from first process");  

  16.         cout<<"First process:"<<memory<<endl;  

  17.         ZeroMemory(&process_info,sizeof(process_info));  

  18.         ZeroMemory(&startup_info,sizeof(startup_info));  

  19.         startup_info.cb=sizeof(startup_info);  

  20.   

  21.         wchar_t cmdline[256];  

  22.         wsprintf(cmdline,L"\"%s\" Child\n",argv[0]);  

  23.         CreateProcessW(argv[0],cmdline,0,0,0,0,0,0,&startup_info,&process_info);  

  24.         WaitForSingleObject(process_info.hProcess,INFINITE);  

  25.           

  26.         UnmapViewOfFile(memory);  

  27.         CloseHandle(filehandle);  

  28.     }  

  29.     else{  

  30.         filehandle=OpenFileMapping(FILE_MAP_ALL_ACCESS,0,ID);  

  31.         memory=(char*)MapViewOfFile(filehandle,FILE_MAP_ALL_ACCESS,0,0,0);  

  32.         cout<<"Second process: "<<memory;  

  33.         UnmapViewOfFile(memory);  

  34.         CloseHandle(filehandle);  

  35.     }  

  36.     getchar();  

  37.     return 0;  

  38. }  



从结果可以看出,子进程连接到共享内存,并能输出父进程存储在那里的字符串。子进程输出字符串以后,就取消内存映射,关闭文件句柄,然后退出。子进程退出后,父进程就可以取消内存映射、关闭文件句柄并退出。


子进程可以继承父进程所有资源的句柄,最简单的方法是通过命令行传递值。


[cpp] view plaincopyprint?

  1. #include <Windows.h>  

  2. #include <tchar.h>  

  3. #include <iostream>  

  4. using namespace std;  

  5. int _tmain(int argc, _TCHAR* argv[]){  

  6.     STARTUPINFO startup_info;  

  7.     PROCESS_INFORMATION process_info;  

  8.     SECURITY_ATTRIBUTES sa;  

  9.     HANDLE filehandle;  

  10.     TCHAR ID[]=TEXT("Local\\sharedmemory");  

  11.     wchar_t* memory;  

  12.     if (argc==1)  

  13.     {  

  14.         //父进程  

  15.         sa.nLength=sizeof(sa);//设置安全属性  

  16.         sa.bInheritHandle=TRUE;//使句柄可以被继承  

  17.         sa.lpSecurityDescriptor=NULL;  

  18.   

  19.         filehandle=CreateFileMapping(INVALID_HANDLE_VALUE,&sa,PAGE_READWRITE,0,1024,ID);  

  20.         memory=(wchar_t*)MapViewOfFile(filehandle,FILE_MAP_ALL_ACCESS,0,0,0);  

  21.         //用共享内存设置命令行  

  22.         swprintf(memory,1024,L"\"%s\" %i",argv[0],filehandle);  

  23.         cout<<"First process memory:"<<memory<<"  handle: "<<filehandle<<endl;  

  24.         ZeroMemory(&process_info,sizeof(process_info));  

  25.         ZeroMemory(&startup_info,sizeof(startup_info));  

  26.         startup_info.cb=sizeof(startup_info);  

  27.   

  28.         //启动子进程  

  29.         CreateProcess(NULL,memory,0,0,true,0,0,0,&startup_info,&process_info);  

  30.         WaitForSingleObject(process_info.hProcess,INFINITE);  

  31.         UnmapViewOfFile(memory);  

  32.         CloseHandle(filehandle);  

  33.     }  

  34.     else{  

  35.         filehandle=(HANDLE)_wtoi(argv[1]);//从argv[1]获得句柄  

  36.         memory=(wchar_t*)MapViewOfFile(filehandle,FILE_MAP_ALL_ACCESS,0,0,0);  

  37.         cout<<"Second process memory : "<<memory<<"  handle: "<<filehandle<<endl;  

  38.         UnmapViewOfFile(memory);  

  39.         CloseHandle(filehandle);  

  40.     }  

  41.     getchar();  

  42.     return 0;  

  43. }  



进程间共享互斥量,可以通过调用CreateMutex或者OpenMutex函数来获取互斥量的句柄。但是,只有一个进程可以创建互斥量,其他的进程只能打开现有的互斥量;互斥量的名称必须唯一;互斥量的名称必须传递给其他进程。

[cpp] view plaincopyprint?

  1. #include <Windows.h>  

  2. #include <tchar.h>  

  3. #include <iostream>  

  4. using namespace std;  

  5. int _tmain(int argc, _TCHAR* argv[]){  

  6.     HANDLE sharedmutex;  

  7.     STARTUPINFO startup_info;  

  8.     PROCESS_INFORMATION process_info;  

  9.     ZeroMemory(&process_info,sizeof(process_info));  

  10.     ZeroMemory(&startup_info,sizeof(startup_info));  

  11.     startup_info.cb=sizeof(startup_info);  

  12.   

  13.     sharedmutex=CreateMutex(0,0,L"mymutex");  

  14.     if (GetLastError()!=ERROR_ALIAS_EXISTS)  

  15.     {  

  16.         if (CreateProcess(argv[0],0,0,0,0,0,0,0,&startup_info,&process_info)==0)  

  17.         {  

  18.             cout<<"Error : "<<GetLastError()<<endl;  

  19.         }  

  20.         WaitForSingleObject(process_info.hProcess,INFINITE);  

  21.     }  

  22.   

  23.     WaitForSingleObject(sharedmutex,INFINITE);  

  24.     for (int i=0;i<100;i++)  

  25.     {  

  26.         cout<<"Process "<<GetCurrentProcessId()<<" count"<<i<<endl;  

  27.     }  

  28.     ReleaseMutex(sharedmutex);  

  29.     CloseHandle(sharedmutex);  

  30.     getchar();  

  31.     return 0;  

  32. }  



使用共享互斥量来确保两个进程中一次只有一个能计数从0数到19,如果没有互斥量的话,那么两个进程可能同时在跑,则控制台的输出将是混合的输出,使用互斥量以后,一次只有一个进程在输出。

 

也可以用管道进行通信,管道是流式通信的一种方式,管道有两种命名管道和匿名管道。匿名管道的创建可以调用CreatePipe(),创建命名管道可以调用CreateNamedPipe(),调用WriteFile通过管道发送数据,ReadFile从管道读取数据。

[cpp] view plaincopyprint?

  1. #include <Windows.h>  

  2. #include <tchar.h>  

  3. #include <process.h>  

  4. #include <iostream>  

  5. #include <stdio.h>  

  6. using namespace std;  

  7. HANDLE readpipe,writepipe;  

  8. unsigned int __stdcall stage1(void * param)  

  9. {  

  10.     char buf[200];  

  11.     DWORD len;  

  12.     for (int i=0;i<10;i++)  

  13.     {  

  14.         sprintf(buf,"Text %i",i);  

  15.         WriteFile(writepipe,buf,strlen(buf)+1,&len,0);  

  16.     }  

  17.     CloseHandle(writepipe);  

  18.     return 0;  

  19. }  

  20. unsigned int __stdcall stage2(void * param)  

  21. {  

  22.     char buf[200];  

  23.     DWORD len;  

  24.     while(ReadFile(readpipe,buf,200,&len,0))  

  25.     {  

  26.         DWORD offset=0;  

  27.         while(offset<len)  

  28.         {  

  29.             cout<<&buf[offset]<<endl;  

  30.             offset+=strlen(&buf[offset])+1;  

  31.         }  

  32.     }  

  33.     CloseHandle(readpipe);  

  34.     return 0;  

  35. }  

  36. int _tmain(int argc, _TCHAR* argv[]){  

  37.     HANDLE thread1,thread2;  

  38.     CreatePipe(&readpipe,&writepipe,0,0);  

  39.     thread1=(HANDLE)_beginthreadex(0,0,&stage1,0,0,0);  

  40.     thread2=(HANDLE)_beginthreadex(0,0,&stage2,0,0,0);  

  41.     WaitForSingleObject(thread1,INFINITE);  

  42.     WaitForSingleObject(thread2,INFINITE);  

  43.     getchar();  

  44.     return 0;  

  45. }  


第一个线程将文本信息放入管道,第二个线程接收并输出这些信息。

还可以用套接字进行通信。WindowsSockets API以BSD Sockets API为基础,与类UNIX操作系统的代码很相似。

[cpp] view plaincopyprint?

  1. #ifndef WIN32_LEAN_AND_MEAN  

  2. #define WIN32_LEAN_AND_MEAN  

  3. #endif  

  4. #include <Windows.h>  

  5. #include <tchar.h>  

  6. #include <process.h>  

  7. #include <WinSock2.h>  

  8. #include <iostream>  

  9. #include <stdio.h>  

  10. #pragma comment(lib,"ws2_32.lib")  

  11. using namespace std;  

  12. HANDLE hevent;  

  13. //响应线程  

  14. void handleecho(void *data)  

  15. {  

  16.     char buf[1024];  

  17.     int count;  

  18.     ZeroMemory(buf,sizeof(buf));  

  19.     int socket=(int)data;  

  20.     while((count=recv(socket,buf,1023,0))>0)  

  21.     {  

  22.         cout<<"received "<<buf<<"from client"<<endl;  

  23.         int ret=send(socket,buf,count,0);  

  24.     }  

  25.     cout<<"close echo thread"<<endl;  

  26.     shutdown(socket,SD_BOTH);  

  27.     closesocket(socket);  

  28. }  

  29. //客户端线程  

  30. unsigned int __stdcall client(void *data)  

  31. {  

  32.     SOCKET ConnectSockket=socket(AF_INET,SOCK_STREAM,0);  

  33.   

  34.     WaitForSingleObject(hevent,INFINITE);  

  35.   

  36.     struct sockaddr_in server;  

  37.     ZeroMemory(&server,sizeof(server));  

  38.     server.sin_family=AF_INET;  

  39.     server.sin_addr.s_addr=inet_addr("192.168.1.107");  

  40.     server.sin_port=7780;  

  41.   

  42.     connect(ConnectSockket,(struct sockaddr*)&server,sizeof(server));  

  43.   

  44.     cout<<"send 'abcd' to server"<<endl;  

  45.     char buf[1024];  

  46.     ZeroMemory(buf,sizeof(buf));  

  47.     strncpy_s(buf,1024,"abcd",5);  

  48.     send(ConnectSockket,buf,strlen(buf)+1,0);  

  49.   

  50.     ZeroMemory(buf,sizeof(buf));  

  51.     recv(ConnectSockket,buf,1024,0);  

  52.     //cout<<"get "<<buf<<"from server"<<endl;  

  53.     printf("get '%s' from server\n",buf);  

  54.   

  55.     cout<<"close client"<<endl;  

  56.     shutdown(ConnectSockket,SD_BOTH);  

  57.     closesocket(ConnectSockket);  

  58.     return 0;  

  59. }  

  60. //服务器线程  

  61. unsigned int __stdcall server(void *data)  

  62. {  

  63.     SOCKET newsocket;  

  64.     SOCKET ServerSocket=socket(AF_INET,SOCK_STREAM,0);  

  65.   

  66.     struct sockaddr_in server;  

  67.     ZeroMemory(&server,sizeof(server));  

  68.     server.sin_family=AF_INET;  

  69.     server.sin_addr.s_addr=INADDR_ANY;  

  70.     server.sin_port=7780;  

  71.   

  72.     bind(ServerSocket,(struct sockaddr*)&server,sizeof(server));  

  73.     listen(ServerSocket,SOMAXCONN);  

  74.   

  75.     SetEvent(hevent);  

  76.   

  77.     while((newsocket=accept(ServerSocket,0,0))!=INVALID_SOCKET)  

  78.     {  

  79.         HANDLE newthread;  

  80.         newthread=(HANDLE)_beginthread(&handleecho,0,(void *)newsocket);  

  81.     }  

  82.   

  83.     cout<<"close server"<<endl;  

  84.     shutdown(ServerSocket,SD_BOTH);  

  85.     closesocket(ServerSocket);  

  86.     return 0;  

  87. }  

  88. //主线程启动客户端线程和服务端线程  

  89. int _tmain(int argc, _TCHAR* argv[]){  

  90.     HANDLE serverthread,clienthread;  

  91.     WSADATA wsaData;  

  92.   

  93.     WSAStartup(MAKEWORD(2,2),&wsaData);  

  94.     hevent=CreateEvent(0,true,0,0);  

  95.   

  96.     serverthread=(HANDLE)_beginthreadex(0,0,&server,0,0,0);  

  97.     clienthread=(HANDLE)_beginthreadex(0,0,&client,0,0,0);  

  98.     WaitForSingleObject(clienthread,INFINITE);  

  99.     CloseHandle(clienthread);  

  100.   

  101.     CloseHandle(hevent);  

  102.     getchar();  

  103.     WSACleanup();  

  104.     return 0;  

  105. }  


服务器线程的第一个操作是打开一个套接字,接着绑定连接。套接字置于监听状态,值SOMAXCONN包含排队等待接受的连接的最大值。然后服务器发信号给事件,事件继而使客户端线程尝试连接。接着,主线程循环等待接受连接,直到收到INVALID_SOCKET的连接。Windows套接字关闭时会发生这种情况。服务器线程在其他线程退出后清理退出。服务器每次接受一个连接时都会创建一个新线程,且新连接的标识会传递给新创建的线程。当循环收到INVALID_SOCKET时,服务器线程关闭,然后关闭套接字。

 


Windows API也提供了很多原子操作,互锁函数。InterlockedIncrement就是一个互锁函数。

[cpp] view plaincopyprint?

  1. #include <Windows.h>  

  2. #include <tchar.h>  

  3. #include <process.h>  

  4. #include <iostream>  

  5. using namespace std;  

  6. int isPrime(int num)    

  7. {    

  8.     int i;    

  9.     for (i=2;i<(int)(sqrt((float)num)+1.0);i++)    

  10.     {    

  11.         if (num%i==0)    

  12.             return 0;    

  13.     }    

  14.     return 1;    

  15. }    

  16. volatile long counter=2;    

  17. unsigned int __stdcall test(void *)    

  18. {    

  19.     while (counter<20)    

  20.     {    

  21.         int num=InterlockedIncrement(&counter);  

  22.         //int num=counter++;    

  23.         printf("Thread ID : %i; value = %i, is prime = %i\n",GetCurrentThreadId(),num,isPrime(num));    

  24.     }    

  25.     return 0;    

  26. }    

  27. int _tmain(int argc,_TCHAR* argv[])    

  28. {    

  29.     HANDLE h1,h2;    

  30.     h1=(HANDLE)_beginthreadex(0,0,&test,(void *)0,0,0);    

  31.     h2=(HANDLE)_beginthreadex(0,0,&test,(void *)0,0,0);    

  32.     WaitForSingleObject(h1,INFINITE);    

  33.     WaitForSingleObject(h2,INFINITE);    

  34.     CloseHandle(h1);    

  35.     CloseHandle(h2);    

  36.     getchar();    

  37.     return 0;    

  38. }   


还有一个问题就是线程本地存储(TLS, ThreadLocal Storage),TLS 是一个机制,利用该机制,程序可以拥有全局变量,但处于“每一线程各不相同”的状态。也就是说,进程中的所有线程都可以拥有全局变量,但这些变量其实是特定对某个线程才有意义,各个线程拥有全局变量的一个副本,各自之间不相影响。每个线程访问数据的方式相同,但看不到其他线程持有的值。比如说,定义一个全局变量int a=10,那么在线程1中对a进行操作a=a-1,如果没用TLS,那么线程2开始获得的a就是9。但是,如果采取了TLS,不管线程1中对a的值进行了如何的修改操作,其他的线程一开始获得的a还是10,不会被修改。这个全局的变量a是没有存储在线程堆栈中的,是在全局的堆栈中,但是却被各个线程“共享”且互不影响。可以认为线程本地存储的本质是“全局”数据的作用域受到了执行线程的限制。

线程本地分配可以调用__declspec、TlsAlloc()等函数。TlsAlloc可以分配全局索引,该索引由所有线程共享,但是每个线程存储在索引中的数据为调用的线程私有,也就是说其他线程看不到持有的值。当不再需要全局索引提供线程本地存储时,可以调用TlsFree来释放全局索引。

给个例子。

[cpp] view plaincopyprint?

  1. #include <Windows.h>  

  2. #include <tchar.h>  

  3. #include <process.h>  

  4. #include <iostream>  

  5. using namespace std;  

  6. DWORD TLSIndex;  

  7. void setdata(int value)  

  8. {  

  9.     cout<<"Thread "<<GetCurrentThreadId()<<": set value = "<<value<<endl;  

  10.     TlsSetValue(TLSIndex,(void*)value);  

  11. }  

  12. void getdata()  

  13. {  

  14.     int value;  

  15.     value=(int)TlsGetValue(TLSIndex);  

  16.     cout<<"Thread "<<GetCurrentThreadId()<<": has value = "<<value<<endl;  

  17. }  

  18. unsigned int __stdcall workthread(void *data)  

  19. {  

  20.     int value=(int)data;  

  21.     cout<<"Thread "<<GetCurrentThreadId()<<": got value = "<<value<<endl;  

  22.     setdata(value);  

  23.     Sleep(1000);  

  24.     getdata();  

  25.     return 0;  

  26. }  

  27. int _tmain(int argc,_TCHAR* argv[])    

  28. {  

  29.     HANDLE h[8];  

  30.     TLSIndex=TlsAlloc();  

  31.     for (int i=0;i<8;i++)  

  32.     {  

  33.         h[i]=(HANDLE)_beginthreadex(0,0,&workthread,(void*)i,0,0);  

  34.     }  

  35.     for (int i=0;i<8;i++)  

  36.     {  

  37.         WaitForSingleObject(h[i],INFINITE);  

  38.     }  

  39.     TlsFree(TLSIndex);  

  40.     getchar();  

  41.     return 0;  

  42. }  


线程本地存储用于保存传给各个线程的值,每个线程在被创建的时候就被传递一个唯一的值,并通过setdata存储在线程本地存储中。getdata可以读取线程本地值,每个线程调用setdata方法,接着休眠1s让其他线程运行,然后调用getdata读取数据。

 

还有个问题,就是优先级的问题。线程的优先级越高,获得的CPU资源(时间)就越多。在有些情况下,调整一个应用程序中不同线程的优先级会非常有用。比如说,当某个应用执行一个长时间的后台任务时,为了保证机器的高响应性,这个后台任务最好以低优先级运行。

Windows操作系统中提供了相关的API。

[cpp] view plaincopyprint?

  1. #include <Windows.h>  

  2. #include <tchar.h>  

  3. #include <process.h>  

  4. #include <iostream>  

  5. #include <time.h>  

  6. using namespace std;  

  7. unsigned int __stdcall fastthread(void *data)  

  8. {  

  9.     double d=1.0;  

  10.     cout<<"fast thread started"<<endl;  

  11.     SetThreadPriority(GetCurrentThread(),THREAD_PRIORITY_ABOVE_NORMAL);  

  12.     clock_t start=clock();  

  13.     for (int i=0;i<1000000000;i++)  

  14.     {  

  15.         d+=i;  

  16.     }  

  17.     clock_t end=clock();  

  18.     cout<<"fast thread finished, it takes "<<(double)(end-start)/CLOCKS_PER_SEC<<"s to finish the task"<<endl;  

  19.     return 0;  

  20. }  

  21. unsigned int __stdcall slowthread(void *data)  

  22. {  

  23.     double d=0.0;  

  24.     cout<<"slow thread started"<<endl;  

  25.     SetThreadPriority(GetCurrentThread(),THREAD_PRIORITY_BELOW_NORMAL);  

  26.     clock_t start=clock();  

  27.     for (int i=0;i<1000000000;i++)  

  28.     {  

  29.         d+=i;  

  30.     }  

  31.     clock_t end=clock();  

  32.     cout<<"slow thread finished, it takes "<<(double)(end-start)/CLOCKS_PER_SEC<<"s to finnish the task"<<endl;  

  33.     return 0;  

  34. }  

  35. int _tmain(int argc,_TCHAR* argv[])    

  36. {  

  37.     HANDLE fast,slow;  

  38.     slow=(HANDLE)_beginthreadex(0,0,&slowthread,0,0,0);  

  39.     fast=(HANDLE)_beginthreadex(0,0,&fastthread,0,0,0);  

  40.     WaitForSingleObject(fast,INFINITE);  

  41.     WaitForSingleObject(slow,INFINITE);  

  42.     getchar();  

  43.     return 0;  

  44. }  



有时候调整线程的优先级会带来优先级反转的问题。

小结

主要实现了windows操作系统中IPC的API,主要有进程之间共享内存、子进程中继承句柄、互斥量、管道、套接字等。此外,还有Windows中的互锁函数。线程本地化存储(TLS)、线程的优先级等。




本文转载自:http://blog.csdn.net/u011000290/article/details/48108557

东风125
粉丝 6
博文 73
码字总数 12747
作品 0
朝阳
高级程序员
私信 提问
windows下进程间通信的手段有哪些?

作者:李志刚 纪玉波 程小茁 崔朝辉 摘 要 随着人们对应用程序的要求越来越高,单进程应用在许多场合已不能满足人们的要求。编写多进程/多线程程序成为现代程序设计的一个重要特点,在多进程...

长平狐
2012/09/20
164
0
一个bug引发惨案!成功追回损失后,拼多多还应做什么?

1月20日凌晨,互联网销售平台拼多多遭遇了“优惠券Bug”:网站每一位注册用户可以通过微信渠道、网页端、QQ渠道等,领取面值为100元的优惠券,该优惠券适用该网站的商品,有效期为一年。随后...

异步社区
02/14
0
0
windows下进程通信的几种方法

1 Windows进程间通信的各种方法 进程是装入内存并准备执行的程序,每个进程都有私有的虚拟地址空间,由代码、数据以及它可利用的系统资源(如文件、管道等)组成。 多进程/多线程是Windows操作...

Davin
2012/10/12
288
0
MoreWindows博客目录(微软最有价值专家,原创技术文章152篇)

为了方便大家查找和学习,现将本人博客中所有博客文章列出目录。 一. 白话经典算法 目前有17篇,分为七大排序和经典面试题讲解两大类 1. 《白话经典算法系列之一 冒泡排序的三种实现》 2. 《...

morewindows
2013/12/24
0
0
windows下进程间通信的方式

1 进程与进程通信   进程是装入内存并准备执行的程序,每个进程都有私有的虚拟地址空间,由代码、数据以及它可利用的系统资源(如文件、管道等)组成。多进程/多线程是Windows操作系统的一个...

技术小阿哥
2017/11/27
0
0

没有更多内容

加载失败,请刷新页面

加载更多

cpu load过高问题排查

load average的概念 top命令中load average显示的是最近1分钟、5分钟和15分钟的系统平均负载。 系统平均负载被定义为在特定时间间隔内运行队列中(在CPU上运行或者等待运行多少进程)的平均进程...

mskk
47分钟前
6
0
用spring boot 实现websocket

import java.io.IOException;import javax.websocket.OnClose;import javax.websocket.OnError;import javax.websocket.OnMessage;import javax.websocket.OnOpen;import java......

jingshishengxu
58分钟前
4
0
shell介绍,命令历史,命令补全和别名,通配符,输入输出重定向,管道符和作业控制

shell介绍 可以使用 yum list |grep zsh 或者 yum list |grep ksh 这样可以搜索 zsh 和 ksh ,有需要的话可以安装 总之,默认使用的就是 .bash shell 命令历史 输入过的命令会被保存在一个文...

doomcat
今天
7
0
1995年的资深工程师,和你谈谈如何进阶

1995年的资深工程师,和你谈谈如何进阶 自我介绍 网络ID:杭城小刘,城市:顾名思义,人在杭州。1995年出生,本科毕业,现在是一名 iOS 资深工程师,年薪 35w。兴趣爱好广泛:乒乓球、美食、...

杭城小刘
今天
10
0
Kafka 面试题

1.Kafka中的ISR、AR代表什么? ISR:与leader保持同步的follower集合 AR:分区的所有副本 2.Kafka中的HW、LEO分别代表什么? LEO:每个副本的最后条消息的offset HW:一个分区中所有副本最小...

djm猿
今天
5
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部