Windows multi-Process Communication API Summary

Source: Internet
Author: User

In a large application system, it is often necessary for multiple processes to work together, and interprocess communication (Ipc,inter process communication) becomes more important. In Linux systems, there are many IPC mechanisms, such as signals (signal), pipelines (pipes), message queues (Messages queue), semaphores (semaphore), and shared memory, sockets ( sockets) , in fact, the Windows operating system also supports these things. In IBM's developerworks found an article about the IPC mechanism API comparison between Windows and Linux, well-written, linked

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

Much of the following is an implementation of the API for these mechanisms.

Create a process

The creation of a process can call the CreateProcess function, CreateProcess has three important parameters, the name of the running process, a pointer to the STARTUPINFO structure, and a pointer to the PROCESS_INFORMATION structure. The prototype is as follows:

BOOL CreateProcess (lpctstrlpapplicationname,lptstr lpcommandline,lpsecurity_attributes lpprocessattributes. Lpsecurity_attributes Lpthreadattributes,bool Binherithandles,dword dwcreationflags,lpvoid LpEnvironment,LPCTSTR Lpcurrentdirectory,lpstartupinfolpstartupinfo,lpprocess_informationlpprocessinformation);

For example, if the application has command-line arguments at startup, the process outputs the command-line arguments and creates a child thread with no parameters, and if not with any parameters, a prompt message is output.

#include <Windows.h> #include <tchar.h> #include <iostream>using namespace std;int _tmain (int argc, _ tchar* argv[]) {startupinfo startup_info; Process_information process_info;if (argc>1) {cout<< "Argument" <<argv[1]<<endl;cout<< " Turn on the sub-thread <<endl; ZeroMemory (&process_info,sizeof (process_info)); ZeroMemory (&startup_info,sizeof (Startup_info)); startup_info.cb=sizeof (startup_info); if (CreateProcess (argv[ 0],0,0,0,0,0,0,0,&startup_info,&process_info) ==0) {cout<< "Error" <<ENDL;} WaitForSingleObject (process_info.hprocess,infinite);} else{cout<< "No arguments" <<ENDL;} GetChar ();}

Give an example, use CreateProcess to open a new thread, start IE browser, open the homepage of Baidu, 5s and then close it.


#include <Windows.h> #include <tchar.h> #include <iostream>using namespace std #define IE L "c:\\ Program files\\internet Explorer\\iexplore.exe "  #define CMD L" open http://www.baidu.com/"  int _tmain (int argc , _tchar* argv[]) {startupinfo startup_info; Getstartupinfo (&startup_info); Process_information Process_info;startup_info.dwflags=startf_useshowwindow;startup_info.wshowwindow=sw_hide;if ( ! CreateProcess (Ie,cmd,null, NULL, FALSE, Create_no_window, NULL, null,&startup_info,&process_info)) {cout< < "Create Process Error:" <<getlasterror () <<endl;return 0;} Sleep (5000); TerminateProcess (process_info.hprocess,0); return 0;}

The handle that was created is returned by Process_info.hprocess. If you pass a parameter to a new process, the first command-line argument must repeat the application name, and the whole line of command is passed to the child process.


Pass parameters to the new process.

#include <Windows.h> #include <tchar.h> #include <iostream>using namespace std;int _tmain (int argc, _ tchar* argv[]) {startupinfo startup_info; Process_information process_info;if (argc==1) {cout<< "No arguments given starting child process" <<endl; wchar_t argument[256];wsprintf (argument,l "\"%s\ "Hello", argv[0]); ZeroMemory (&process_info,sizeof (process_info)); ZeroMemory (&startup_info,sizeof (Startup_info)); startup_info.cb=sizeof (startup_info); if (CreateProcess (argv[ 0],argument,0,0,0,0,0,0,&startup_info,&process_info) ==0) {cout<< "Error" <<GetLastError () < <endl;} WaitForSingleObject (process_info.hprocess,infinite);} else{cout<< "Argument" <<ARGV[1]<<ENDL;} GetChar ();}



Ipc

The memory can be shared between processes, and after a process establishes a region of memory with shared properties, another process can open the area of memory and map it to its own address space. Shared memory can use the file mapping function createfilemapping to create a handle to a shared memory region, map this area to a process through MapViewOfFile (), and then connect to an existing shared memory region. Handles can be obtained through openfilemapping. After the process has used shared memory, you need to call UnmapViewOfFile () to Unmap, and then call CloseHandle () to close the appropriate handle to avoid a memory leak.

For example, if the application starts with no parameters, the application creates a child process. The parent process will also establish a shared memory region and save a string to the shared memory. The shared memory is named Sharedmemory and is created in the Local\ namespace, that is, the shared memory is visible to all processes of that user. (The namespace of the process is divided into two, the global namespace begins with the global\ identifier, and the local namespace starts with local\)

#include <Windows.h> #include <tchar.h> #include <iostream>using namespace std;int _tmain (int argc, _ tchar* argv[]) {startupinfo startup_info; Process_information Process_info; HANDLE FileHandle; TCHAR id[]=text ("Local\\sharedmemory"); char* memory;if (argc==1) {filehandle=createfilemapping (INVALID_HANDLE_ Value,null,page_readwrite,0,1024,id); memory= (char*) mapviewoffile (filehandle,file_map_all_access,0,0,0); sprintf _s (memory,1024, "%s", "Data from First process");cout<< "first process:" <<memory<<endl; ZeroMemory (&process_info,sizeof (process_info)); ZeroMemory (&startup_info,sizeof (Startup_info)); startup_info.cb=sizeof (startup_info); wchar_t cmdline[256]; wsprintf (cmdline,l "\"%s\ "child\n", argv[0]); CREATEPROCESSW (Argv[0],cmdline,0,0,0,0,0,0,&startup_info,&process_info); WaitForSingleObject (Process_info.hprocess,infinite); UnmapViewOfFile (memory); CloseHandle (filehandle);} Else{filehandle=openfilemapping (File_map_all_access,0,id); memory= (char*) MapViewOfFile (filehandle,file_map_all_access,0,0,0);cout<< "Second process:" <<memory; UnmapViewOfFile (memory); CloseHandle (filehandle);} GetChar (); return 0;}



As you can see from the results, the child process is connected to the shared memory and can output the string where the parent process is stored. After the child process output string, it cancels the memory map, closes the file handle, and then exits. After the child process exits, the parent process can cancel the memory map, close the file handle, and exit.


A child process can inherit a handle to all the resources of the parent process, and the simplest method is to pass the value through the command line.


#include <Windows.h> #include <tchar.h> #include <iostream>using namespace std;int _tmain (int argc, _ tchar* argv[]) {startupinfo startup_info; Process_information Process_info; Security_attributes sa; HANDLE FileHandle; TCHAR id[]=text ("Local\\sharedmemory"); wchar_t* memory;if (argc==1) {//Parent process sa.nlength=sizeof (SA);// Set the security property sa.binherithandle=true;//the handle can be inherited sa.lpsecuritydescriptor=null;filehandle=createfilemapping (INVALID_ Handle_value,&sa,page_readwrite,0,1024,id); memory= (wchar_t*) mapviewoffile (filehandle,file_map_all_access, 0,0,0);//SET command line swprintf with shared memory (memory,1024,l "\"%s\ "%i", Argv[0],filehandle);cout<< "First process memory:" < <memory<< "Handle:" <<filehandle<<endl; ZeroMemory (&process_info,sizeof (process_info)); ZeroMemory (&startup_info,sizeof (Startup_info)); startup_info.cb=sizeof (startup_info);//Start child process CreateProcess ( Null,memory,0,0,true,0,0,0,&startup_info,&process_info); WaitForSingleObject (Process_info.hprocess,infinite); UnmapviewOffile (memory); CloseHandle (filehandle);} Else{filehandle= (HANDLE) _wtoi (argv[1]),//from argv[1] Get handle memory= (wchar_t*) mapviewoffile (Filehandle,file_map_all_ access,0,0,0);cout<< "Second process Memory:" <<memory<< "Handle:" <<filehandle<<endl; UnmapViewOfFile (memory); CloseHandle (filehandle);} GetChar (); return 0;}



Shared mutex between processes, you can get a handle to the mutex by calling the CreateMutex or OpenMutex function. However, only one process can create mutexes, other processes can only open existing mutexes, the name of the mutex must be unique, and the name of the mutex must be passed to other processes.

#include <Windows.h> #include <tchar.h> #include <iostream>using namespace std;int _tmain (int argc, _ tchar* argv[]) {HANDLE Sharedmutex; Startupinfo Startup_info; Process_information Process_info; ZeroMemory (&process_info,sizeof (process_info)); ZeroMemory (&startup_info,sizeof (Startup_info)); startup_info.cb=sizeof (startup_info); sharedmutex= CreateMutex (0,0,l "Mymutex"); if (GetLastError ()!=error_alias_exists) {if (CreateProcess, &startup_info,&process_info) ==0) {cout<< "Error:" <<getlasterror () <<endl;} WaitForSingleObject (process_info.hprocess,infinite);} WaitForSingleObject (Sharedmutex,infinite); for (int i=0;i<100;i++) {cout<< "Process" << GetCurrentProcessId () << "Count" <<i<<endl;} ReleaseMutex (Sharedmutex); CloseHandle (Sharedmutex); GetChar (); return 0;}



Using shared mutexes to ensure that only one of two processes can count from 0 to 19, if there is no mutex, then two processes may be running at the same time, then the output of the console will be mixed output, after using mutexes, only one process at a time is output.

Pipelines can also be used to communicate, and pipelines are a way of streaming, with two named pipes and anonymous pipes in the pipeline. Anonymous pipe creation can call CreatePipe (), create a named pipe to call CreateNamedPipe (), call WriteFile to send data through a pipeline, ReadFile read data from the pipeline.

#include <Windows.h> #include <tchar.h> #include <process.h> #include <iostream> #include < Stdio.h>using namespace Std; HANDLE readpipe,writepipe;unsigned int __stdcall stage1 (void * param) {char buf[200];D word len;for (int i=0;i<10;i++) { sprintf (buf, "Text%i", i); WriteFile (Writepipe,buf,strlen (BUF) +1,&len,0);} CloseHandle (writepipe); return 0;} unsigned int __stdcall stage2 (void * param) {char buf[200];D word len;while (ReadFile (readpipe,buf,200,&len,0)) { DWORD Offset=0;while (Offset<len) {Cout<<&buf[offset]<<endl;offset+=strlen (&buf[offset]) +1 ;}} CloseHandle (readpipe); return 0;} int _tmain (int argc, _tchar* argv[]) {HANDLE thread1,thread2; CreatePipe (&readpipe,&writepipe,0,0); thread1= (HANDLE) _beginthreadex (0,0,&stage1,0,0,0); Thread2= ( HANDLE) _beginthreadex (0,0,&stage2,0,0,0); WaitForSingleObject (Thread1,infinite); WaitForSingleObject (Thread2,infinite); GetChar (); return 0;}

The first thread puts the text information into the pipeline, and the second thread receives and outputs the information.

You can also use sockets for communication. The WindowsSockets API is based on the BSD Sockets API and is similar to the Code for UNIX-like operating systems.

#ifndef win32_lean_and_mean#define win32_lean_and_mean#endif#include <Windows.h> #include <tchar.h># Include <process.h> #include <WinSock2.h> #include <iostream> #include <stdio.h> #pragma Comment (lib, "Ws2_32.lib") using namespace std; HANDLE hevent;//response thread void Handleecho (void *data) {char buf[1024];int count; ZeroMemory (buf,sizeof (BUF)); int socket= (int) data;while ((Count=recv (socket,buf,1023,0)) >0) {cout<< " Received "<<buf<< from client" <<endl;int ret=send (socket,buf,count,0);} cout<< "Close echo Thread" <<endl;shutdown (Socket,sd_both); closesocket (socket);} Client thread unsigned int __stdcall client (void *data) {SOCKET connectsockket=socket (af_inet,sock_stream,0); WaitForSingleObject (hevent,infinite); struct sockaddr_in server; ZeroMemory (&server,sizeof (server)); SERVER.SIN_FAMILY=AF_INET;SERVER.SIN_ADDR.S_ADDR=INET_ADDR (" 192.168.1.107 "); Server.sin_port=7780;connect (Connectsockket, (struct sockaddr*) &server,sizeof (server)); cout << "send ' ABCD ' to Server" <<endl;char buf[1024]; ZeroMemory (buf,sizeof (BUF)) strncpy_s (buf,1024, "ABCD", 5); Send (Connectsockket,buf,strlen (BUF) +1,0); ZeroMemory (buf,sizeof (BUF)); recv (connectsockket,buf,1024,0);//cout<< "Get" <<buf<< "from server" <<endl;printf ("Get '%s ' from server\n", buf);cout<< "Close Client" <<endl;shutdown (Connectsockket, Sd_both); closesocket (connectsockket); return 0;} Server thread unsigned int __stdcall server (void *data) {SOCKET newsocket; SOCKET Serversocket=socket (af_inet,sock_stream,0); struct sockaddr_in server; ZeroMemory (&server,sizeof (server)); server.sin_family=af_inet;server.sin_addr.s_addr=inaddr_any;server.sin_ Port=7780;bind (ServerSocket, (struct sockaddr*) &server,sizeof (server)); listen (serversocket,somaxconn); SetEvent (hevent); while ((Newsocket=accept (serversocket,0,0))!=invalid_socket) {HANDLE newthread;newthread= (HANDLE ) _beginthread (&handleecho,0, (void *) newsocket);} cout<< "Close Server" <<endl;shutdown (ServerSOcket,sd_both); closesocket (serversocket); return 0;} The main thread starts the client thread and service threads int _tmain (int argc, _tchar* argv[]) {HANDLE serverthread,clienthread; Wsadata Wsadata; WSAStartup (Makeword (2,2), &wsadata); Hevent=createevent (0,true,0,0); serverthread= (HANDLE) _beginthreadex (0,0, &server,0,0,0); clienthread= (HANDLE) _beginthreadex (0,0,&client,0,0,0); WaitForSingleObject (Clienthread,infinite); CloseHandle (Clienthread); CloseHandle (hevent); GetChar (); WSACleanup (); return 0;}

The first action of a server thread is to open a socket and then bind the connection. The socket is placed in the listening state, and the value Somaxconn contains the maximum number of connections queued for acceptance. The server then signals the event, which in turn causes the client thread to attempt to connect. The main thread loop waits for the connection to be accepted until the Invalid_socket connection is received. This happens when Windows Sockets are closed. The server thread clears out after another thread exits. The server creates a new thread each time a connection is accepted, and the identity of the new connection is passed to the newly created thread. When the loop receives Invalid_socket, the server thread shuts down and then closes the socket.


The Windows API also provides a number of atomic operations, interlocked functions. InterlockedIncrement is an interlock function.

#include <Windows.h> #include <tchar.h> #include <process.h> #include <iostream>using namespace std;int isprime (int num)  {  int i;  for (i=2;i< (int) (sqrt (float) num) +1.0) (i++)  {  if (num%i==0)  return 0;  }  return 1;  }  volatile long counter=2;  unsigned int __stdcall test (void *)  {while  (counter<20)  {  int num=interlockedincrement (& counter);//int num=counter++;  printf ("Thread ID:%i; Value =%i, is prime =%i\n ", GetCurrentThreadID (), Num,isprime (num));  }  return 0;  }  int _tmain (int argc,_tchar* argv[])  {  HANDLE h1,h2;  h1= (HANDLE) _beginthreadex (0,0,&test, (void *) 0,0,0);  H2= (HANDLE) _beginthreadex (0,0,&test, (void *) 0,0,0);  WaitForSingleObject (h1,infinite);  WaitForSingleObject (h2,infinite);  CloseHandle (H1);  CloseHandle (H2);  GetChar ();  return 0;  

Another problem is thread-local storage (TLS, ThreadLocal Storage), which is a mechanism by which programs can have global variables but are in a state of "each thread is different". That is, all threads in a process can have global variables, but these variables are specific to a thread, and each thread has a copy of the global variable, which does not affect each other. Each thread accesses the data in the same way, but does not see the values held by other threads. For example, to define a global variable int a=10, then A is manipulated in thread 1 a=a-1, and if TLS is not used, then thread 2 starts with a that is 9. However, if TLS is taken, no matter how the value of a in thread 1 is modified, the other thread will get a or 10 at the beginning, and it won't be modified. This global variable A is not stored in the thread stack, but is in the global stack, but is "shared" by individual threads and does not affect each other. You can assume that the nature of thread-local storage is that the scope of the "global" data is limited by the execution thread.

Thread-Local allocation can call functions such as __declspec, TlsAlloc (), and so on. TlsAlloc can assign a global index that is shared by all threads, but the data that each thread stores in the index is private to the calling thread, which means that other threads do not see the value held. When the global index is no longer required to provide thread-local storage, you can call TlsFree to release the global index.

Give an example.

#include <Windows.h> #include <tchar.h> #include <process.h> #include <iostream>using namespace Std;dword tlsindex;void SetData (int value) {cout<< "Thread" <<getcurrentthreadid () << ": Set Value = "<<value<<endl; TlsSetValue (TlsIndex, (void*) value);} void GetData () {int value;value= (int) tlsgetvalue (tlsindex);cout<< "Thread" <<getcurrentthreadid () < < ": Has value =" <<VALUE<<ENDL;} unsigned int __stdcall workthread (void *data) {int value= (int) data;cout<< "Thread" <<getcurrentthreadid () << ": Got value =" <<value<<endl;setdata (value); Sleep (+); GetData (); return 0;} int _tmain (int argc,_tchar* argv[])  {HANDLE h[8]; Tlsindex=tlsalloc (); for (int i=0;i<8;i++) {h[i]= (HANDLE) _beginthreadex (0,0,&workthread, (void*) i,0,0);} for (int i=0;i<8;i++) {WaitForSingleObject (h[i],infinite);} TlsFree (TlsIndex); GetChar (); return 0;}

Thread-local storage is used to hold values passed to individual threads, each of which is passed a unique value when it is created, and stored in a thread-local store via SetData. GetData can read thread-local values, each thread calls the SetData method, and then hibernate 1s lets other threads run and then calls GetData to read the data.

There is one more problem, the priority problem. The higher the priority of the thread, the more CPU resources (time) are obtained. In some cases, it is useful to adjust the priority of different threads in an application. For example, when an application performs a long background task, the background task is best to run at a low priority in order to ensure a high level of responsiveness of the machine.

The relevant APIs are available in the Windows operating system.

#include <Windows.h> #include <tchar.h> #include <process.h> #include <iostream> #include < time.h>using namespace std;unsigned int __stdcall fastthread (void *data) {double d=1.0;cout<< "fast thread Started "<<endl; SetThreadPriority (GetCurrentThread (), thread_priority_above_normal); clock_t Start=clock (); for (int i=0;i< 1000000000;i++) {d+=i;} clock_t End=clock ();cout<< "Fast thread finished, it takes" << (double) (End-start)/clocks_per_sec<< " s to finish the task "<<endl;return 0;} unsigned int __stdcall slowthread (void *data) {double d=0.0;cout<< "slow thread Started" <<endl; SetThreadPriority (GetCurrentThread (), thread_priority_below_normal); clock_t Start=clock (); for (int i=0;i< 1000000000;i++) {d+=i;} clock_t End=clock ();cout<< "Slow thread finished, it takes" << (double) (End-start)/clocks_per_sec<< " s to Finnish the task "<<endl;return 0;} int _tmain (int argc,_tchar* argv[]) {HANDLE fast,slow;slow= (HANDLE) _beginthreadex (0,0,&slowthread,0,0,0); fast= (HANDLE) _beginthreadex (0,0,&fastthread,0,0,0); WaitForSingleObject (Fast,infinite); WaitForSingleObject (Slow,infinite); GetChar (); return 0;}


Sometimes adjusting the priority of a thread can lead to a priority reversal problem.

Summary

The main implementation of the Windows operating system IPC API, mainly in the process of sharing memory, child process inheritance handle, mutex, pipeline, socket and so on. In addition, there are interlocked functions in Windows. Thread-Localized storage (TLS), thread priority, and so on.




Copyright NOTICE: This article for Bo Master original article, without Bo Master permission not reproduced.

Windows multi-Process Communication API Summary

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.