windows C++進程間和線程間通信


Thank Swarajya Pendharkar and MSDN very much

進程間通信

進程基本概念

In computer science, inter-process communication or interprocess communication (IPC) refers specifically to the mechanisms an operating system provides to allow processes it manages to share data. Typically, applications can use IPC categorized as clients and servers, where the client requests data and the server responds to client requests.Many applications are both clients and servers, as commonly seen in distributed computing. Methods for achieving IPC are divided into categories which vary based on software requirements, such as performance and modularity requirements, and system circumstances, such as network bandwidth and latency.

Approaches

Method Short Description Provided by (operating systems or other environments)
File A record stored on disk, or a record synthesized on demand by a file server, which can be accessed by multiple processes. Most operating systems
Signal; also Asynchronous System Trap A system message sent from one process to another, not usually used to transfer data but instead used to remotely command the partnered process. Most operating systems
Socket A data stream sent over a network interface, either to a different process on the same computer or to another computer on the network. Typically byte-oriented, sockets rarely preserve message boundaries. Data written through a socket requires formatting to preserve message boundaries. Most operating systems
Message queue A data stream similar to a socket, but which usually preserves message boundaries. Typically implemented by the operating system, they allow multiple processes to read and write to the message queue without being directly connected to each other. Most operating systems
Pipe A unidirectional data channel. Data written to the write end of the pipe is buffered by the operating system until it is read from the read end of the pipe. Two-way data streams between processes can be achieved by creating two pipes utilizing standard input and output. All POSIX systems, Windows
Named pipe A pipe implemented through a file on the file system instead of standard input and output. Multiple processes can read and write to the file as a buffer for IPC data. All POSIX systems, Windows, AmigaOS 2.0+
Semaphore A simple structure that synchronizes multiple processes acting on shared resources. All POSIX systems, Windows, AmigaOS
Shared memory Multiple processes are given access to the same block of memory which creates a shared buffer for the processes to communicate with each other. All POSIX systems, Windows
Message passing Allows multiple programs to communicate using message queues and/or non-OS managed channels, commonly used in concurrency models. Used in RPC, RMI, and MPI paradigms, Java RMI, CORBA, DDS, MSMQ, MailSlots, QNX, others
Memory-mapped file A file mapped to RAM and can be modified by changing memory addresses directly instead of outputting to a stream. This shares the same benefits as a standard file. All POSIX systems, Windows

進程間通信(IPC)實現

The following IPC mechanisms are supported by Windows:

  • Clipboard
  • COM
  • Data Copy
  • DDE
  • File Mapping
  • Mailslots
  • Pipes
  • RPC
  • Windows Sockets

進程間通信之共享內存實現

File mapping enables a process to treat the contents of a file as if they were a block of memory in the process’s address space. The process can use simple pointer operations to examine and modify the contents of the file. When two or more processes access the same file mapping, each process receives a pointer to memory in its own address space that it can use to read or modify the contents of the file. The processes must use a synchronization object, such as a semaphore, to prevent data corruption in a multitasking environment.


Following are some of the Win32 APIs that are used when working with shared memory (memory mapped objects):

  • CreateFileMapping()
  • MapViewOfFile()
  • UnMapViewOfFile()
  • CloseHandle()

Key Point: Mailslots offer an easy way for applications to send and receive short messages. They also provide the ability to broadcast messages across all computers in a network domain.


#include <iostream>
#include <Windows.h>
#include <tchar.h>
#include <stdio.h>

using namespace std;
//-------------------------------
#define MAX_SH_MEM_SIZE             1024
#define MAX_READ_PROCESSES_ALLOWED  3
#define WAIT_TIME_OUT               100
//-------------------------------

//-------------------------------
/*
Global variables
*/


HANDLE  g_hReadEvent[MAX_READ_PROCESSES_ALLOWED];
TCHAR   g_szReadEventName[] = _T("My Read Event");

HANDLE  g_hWriteEvent = NULL;
TCHAR   g_szWriteEventName[] = _T("My Write Event");

HANDLE  g_hSharedMemory = NULL;
LPTSTR  g_pBuffer = NULL;
TCHAR   g_szSharedMemoryName[] = _T("My Shared Memory");

bool    Initialize();
void    DeInitialize();
void    DisplayOptions();
bool    RecvAndProcessOption();
void    WriteAndPrint();
void    ReadAndPrint();

int main(int argv, char* argc[], char* env[]){
    if (Initialize()){
        std::cout << "Initialization of process was successful" << endl;
    }
    else
    {
        DeInitialize();
        std::cout << "Initialization of the process was not successful" << endl;
        return 1;
    }

    bool bContinue = true;
    while (bContinue){
        DisplayOptions();
        bContinue = RecvAndProcessOption();
    }
    DeInitialize();
}

bool    Initialize(){
    for (int i = 0; i < MAX_READ_PROCESSES_ALLOWED; i++)
    {
        g_hReadEvent[i] = NULL;
    }
    TCHAR szBuffer[32];
    /*
    原型
    int sprintf( char *buffer, const char *format, [ argument] … );
    參數列表
    buffer:char型指針,指向將要寫入的字符串的緩衝區。
    format:格式化字符串。
    [argument]...:可選參數,可以是任何類型的數據。
    返回值
    返回寫入buffer 的字符數,出錯則返回-1. 如果 buffer 或 format 是空指針,且不出錯而繼續,函數將返回-1,並且 errno 會被設置爲 EINVAL。
    sprintf 返回被寫入buffer 的字節數,結束字符‘\0’不計入內。即,如果“Hello”被寫入空間足夠大的buffer後,函數sprintf 返回5。
    */
    for (int i = 0; i < MAX_READ_PROCESSES_ALLOWED; i++)
    {
        _stprintf_s(szBuffer, _T("%s %d"), g_szReadEventName, i);
        g_hReadEvent[i] = CreateEvent(NULL, false, true, szBuffer);
        if (NULL == g_hReadEvent[i]){
            return false;
        }
    }
    /*
    HANDLE CreateEvent(
    LPSECURITY_ATTRIBUTESlpEventAttributes,// 安全屬性
    BOOLbManualReset,// 復位方式
    BOOLbInitialState,// 初始狀態
    LPCTSTRlpName // 對象名稱 事件對象的名稱
    );

    如果函數調用成功,函數返回事件對象的句柄。如果對於命名的對象,在函數調用前已經被創建,函數將返回存在的事件對象的句柄,而且在GetLastError函數中返回ERROR_ALREADY_EXISTS。
    如果函數失敗,函數返回值爲NULL,如果需要獲得詳細的錯誤信息,需要調用GetLastError。
    */
    g_hWriteEvent = CreateEvent(NULL, false, true, g_szWriteEventName);
    if (NULL == g_hWriteEvent){
        return false;
    }
    /*函數原型
    HANDLE WINAPI CreateFileMapping(
    _In_HANDLE hFile,
    _In_opt_LPSECURITY_ATTRIBUTES lpAttributes,
    _In_DWORD flProtect,
    _In_DWORD dwMaximumSizeHigh,
    _In_DWORD dwMaximumSizeLow,
    _In_opt_LPCTSTR lpName);
    創建一個新的文件映射內核對象。
    */
    g_hSharedMemory = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, MAX_SH_MEM_SIZE, g_szSharedMemoryName);
    if (NULL == g_hSharedMemory || INVALID_HANDLE_VALUE == g_hSharedMemory){
        std::cout << "Error occured while creating file mapping object:" << GetLastError() << endl;
        return false;
    }
    /*
    函數原型
    LPVOID WINAPI MapViewOfFile(
    __in HANDLE hFileMappingObject,
    __in DWORD dwDesiredAccess,
    __in DWORD dwFileOffsetHigh,
    __in DWORD dwFileOffsetLow,
    __in SIZE_T dwNumberOfBytesToMap
    );
    MapViewOfFile,計算機語言。將一個文件映射對象映射到當前應用程序的地址空間。MapViewOfFileEx允許我們指定一個基本地址來進行映射。
    參數1:hFileMappingObject 爲CreateFileMapping()返回的文件映像對象句柄。
    參數2:dwDesiredAccess 映射對象的文件數據的訪問方式,而且同樣要與CreateFileMapping()函數所設置的保護屬性相匹配。 可取以下值:
    FILE_MAP_ALL_ACCESS 等價於CreateFileMapping的 FILE_MAP_WRITE|FILE_MAP_READ. 文件映射對象被創建時必須指定PAGE_READWRITE 選項.
    FILE_MAP_COPYA 可以讀取和寫入文件.寫入操作會導致系統爲該頁面創建一份副本.在調用CreateFileMapping時必須傳入PAGE_WRITECOPY保護屬性.
    FILE_MAP_EXECUTE 可以將文件中的數據作爲代碼來執行.在調用CreateFileMapping時可以傳入PAGE_EXECUTE_READWRITE或PAGE_EXECUTE_READ保護屬性.
    FILE_MAP_READ 可以讀取文件.在調用CreateFileMapping時可以傳入PAGE_READONLY或PAGE_READWRITE保護屬性.
    FILE_MAP_WRITEA 可以讀取和寫入文件.在調用CreateFileMapping時必須傳入PAGE_READWRITE保護屬性.
    參數3:dwFileOffsetHigh 表示文件映射起始偏移的高32位.
    參數4:dwFileOffsetLow 表示文件映射起始偏移的低32位.(64KB對齊不是必須的)
    參數5:dwNumberOfBytes 指定映射文件的字節數.

    */
    g_pBuffer = (LPTSTR)MapViewOfFile(g_hSharedMemory, FILE_MAP_ALL_ACCESS, 0, 0, MAX_SH_MEM_SIZE);
    if (NULL == g_pBuffer){
        std::cout << "Error occured while mapping view of the file:" << GetLastError() << endl;
        return false;
    }
    return true;
}


void    DeInitialize(){
    for (int i = 0; i < MAX_READ_PROCESSES_ALLOWED; i++)
    {
        CloseHandle(g_hReadEvent[i]);
    }
    CloseHandle(g_hWriteEvent);
    UnmapViewOfFile(g_pBuffer);
    CloseHandle(g_hSharedMemory);
}

void DisplayOptions(){
    cout << "--------------------------------------------------------------" << endl;
    cout << "------------Operation on Share Memory--(Read/Write)-----------" << endl;
    cout << "------------Enter 1 to write to the shared memory-------------" << endl;
    cout << "------------Enter 2 to read the shared memory-----------------" << endl;
    cout << "------------Enter 3 to exit the application-------------------" << endl;
    cout << "--------------------------------------------------------------" << endl;
    cout << "Enter option:";
}

bool RecvAndProcessOption(){
    int nInput;
    bool bReturnValue = true;
    cin >> nInput;
    switch (nInput){
    case 1:
        cout << "Write Operation selected" << endl;
        WriteAndPrint();
        bReturnValue = true;
        break;
    case 2:
        cout << "Read Operation selected" << endl;
        ReadAndPrint();
        bReturnValue = true;
        break;
    case 3:
        cout << "Quit Operation selected" << endl;
        bReturnValue = false;
        break;
    default:
        cout << "Invalid Operation selected" << endl;
        bReturnValue = true;
        break;
    }
    return  bReturnValue;
}

void WriteAndPrint(){
    cout << "Trying to write operation to complete..." << endl;
    /**
    DWORD WINAPI WaitForSingleObject(
    __in HANDLE hHandle,
    __in DWORD dwMilliseconds
    );
    hHandle[in]對象句柄。可以指定一系列的對象,如Event、Job、Memory resource notification、Mutex、Process、Semaphore、Thread、Waitable timer等。
    dwMilliseconds[in]定時時間間隔,單位爲milliseconds(毫秒).
    如果指定一個非零值,函數處於等待狀態直到hHandle標記的對象被觸發,或者時間到了。
    如果dwMilliseconds爲0,對象沒有被觸發信號,函數不會進入一個等待狀態,它總是立即返回。
    如果dwMilliseconds爲INFINITE,對象被觸發信號後,函數纔會返回。

    返回值:
    WAIT_ABANDONED 0x00000080:當hHandle爲mutex時,如果擁有mutex的線程在結束時沒有釋放核心對象會引發此返回值。
    WAIT_OBJECT_0 0x00000000 :指定的對象表現爲有信號狀態
    WAIT_TIMEOUT 0x00000102:等待超時
    WAIT_FAILED 0xFFFFFFFF :出現錯誤,可通過GetLastError得到錯誤代碼
    */
    if (WAIT_OBJECT_0 == WaitForSingleObject(g_hWriteEvent, INFINITE)){
        cout << "Waiting for all read Operations to complete..." << endl;
        /*
        原型:DWORD WaitForMultipleObjects(
        DWORD nCount,
        const HANDLE* lpHandles,
        BOOL bWaitAll,
        DWORD dwMilliseconds
        );
        如果函數成功,返回值表示該事件導致該函數返回。這個值可以是下列之一。
        ValueMeaning
        WAIT_OBJECT_0到(WAIT_OBJECT_0 + nCount - 1如果bWaitAll爲TRUE),則返回值表明所有指定對象的狀態信號。
        如果bWaitAll爲FALSE,則返回值減去不是WAIT_OBJECT_0表示lpHandles數組的對象的滿意指數的等待。如果多個對象在通話過程中信號成爲,這是與所有的信號對象的最小索引值的信號對象的數組索引。
        WAIT_ABANDONED_0至(WAIT_ABANDONED_0 + nCount - 1)如果bWaitAll爲TRUE,則返回值表明所有指定對象的狀態是觸發的,並且至少對象之一,是一個廢棄的互斥對象。
        If bWaitAll is FALSE, the return value minus WAIT_ABANDONED_0 indicates the lpHandles array index of an abandoned mutex object that satisfied the wait
        如果bWaitAll爲FALSE,則返回值減去WAIT_ABANDONED_0 表示一個廢棄的互斥對象在lpHandles數組中的下標,滿足等待。
        WAIT_TIMEOUTThe超時間隔已過,由bWaitAll參數指定的條件得不到滿足。
        */
        DWORD dwWaitReadResult = WaitForMultipleObjects(MAX_READ_PROCESSES_ALLOWED, g_hReadEvent, TRUE, INFINITE);
        if (WAIT_OBJECT_0 == dwWaitReadResult){
            cout << "Enter a string (without spaces):";
            char c_text[100];
            //cin >> strText;
            //gets(c_text);
            fflush(stdin); //清空輸入緩衝區 c++
            /**
            stdin
            std = stand     in = input 
            stdin 就是標準輸入設備,一般地就是鍵盤了
            stdin是重向定義,
            定義爲標準輸入設備(即健盤)
            stdout
            標準輸出設備(顯示器)
            函數原型
            char *fgets(char *buf, int bufsize, FILE *stream);
            參數
            *buf: 字符型指針,指向用來存儲所得數據的地址。
            bufsize: 整型數據,指明存儲數據的大小。
            *stream: 文件結構體指針,將要讀取的文件流。
            */
            fgets(c_text, 100, stdin);

            //g_pBuffer=(LPTSTR)(LPCSTR)c_text;
            CopyMemory(g_pBuffer, c_text, strlen(c_text));
            cout << "Shared Memory:" << g_pBuffer << endl;
        }
        else{
            cout << "Error occured while waiting:" << GetLastError() << endl;
        }
        cout << "Setting the Write Event..." << endl;
        SetEvent(g_hWriteEvent);
        cout << "Setting the Read Events..." << endl;
        for (int i = 0; i < MAX_READ_PROCESSES_ALLOWED; i++)
        {
            SetEvent(g_hReadEvent[i]);
        }
    }
    else{
        cout << "Error occured while waiting:"<<GetLastError() << endl;
    }
}

void ReadAndPrint(){
    cout << "Trying to read and print the shared memory..." << endl;
    bool bContinue = true;
    while (bContinue){
        cout << "Waiting for write operation to complete..." << endl;
        DWORD dwWaitResult = WaitForSingleObject(g_hWriteEvent, INFINITE);
        if (WAIT_OBJECT_0 == dwWaitResult){
            bool bEventFound = false;
            for (int i = 0; i < MAX_READ_PROCESSES_ALLOWED; i++)
            {
                DWORD dwWaitResult = WaitForSingleObject(g_hReadEvent[i], WAIT_TIME_OUT);
                if (WAIT_OBJECT_0 == dwWaitResult){
                    bEventFound = true;
                    cout << "Setting the Write Event..." << endl;
                    SetEvent(g_hWriteEvent);
                    cout << "Setting the Write Event..." << endl;
                    SetEvent(g_hWriteEvent);

                    cout << "Shared Memory:" << g_pBuffer << endl;
                    cout << "Setting the Read Event..." << endl;
                    SetEvent(g_hReadEvent[i]);
                    bContinue = false;
                    break;
                }
                else
                {
                    continue;
                }
            }
            if (false == bEventFound){
                cout << "Setting the Write Event..." << endl;
                SetEvent(g_hWriteEvent);
                Sleep(WAIT_TIME_OUT);
            }
        }
        else
        {
            cout << "Error occured while waiting:"<<GetLastError() << endl;
        }
    }
}

Notes:

  • Source code is platform dependent.
  • Can only be used for processes that are on the same computer.
  • Once a memory mapped object is mapped into the process area, using it is very straightforward and easy.
  • Perhaps the fastest IPC mechanism.

進程間通信之命名管道實現

There are two types of pipes for two-way communication: anonymous pipes and named pipes.

Anonymous pipes enable related processes to transfer information to each other. Typically, an anonymous pipe is used for redirecting the standard input or output of a child process so that it can exchange data with its parent process. To exchange data in both directions (duplex operation), you must create two anonymous pipes. The parent process writes data to one pipe using its write handle, while the child process reads the data from that pipe using its read handle. Similarly, the child process writes data to the other pipe and the parent process reads from it. Anonymous pipes cannot be used over a network, nor can they be used between unrelated processes.

Named pipes are used to transfer data between processes that are not related processes and between processes on different computers. Typically, a named-pipe server process creates a named pipe with a well-known name or a name that is to be communicated to its clients. A named-pipe client process that knows the name of the pipe can open its other end, subject to access restrictions specified by named-pipe server process. After both the server and client have connected to the pipe, they can exchange data by performing read and write operations on the pipe.

Key Point: Anonymous pipes provide an efficient way to redirect standard input or output to child processes on the same computer. Named pipes provide a simple programming interface for transferring data between two processes, whether they reside on the same computer or over a network.


Pipes are FIFO in behavior (First-In, First-Out). Pipes are of two types – Anonymous Pipes and Named Pipes.

An Anonymous Pipe is created using the CreatePipe() API. An anonymous pipe is local, and cannot be used to communicate over a network. An anonymous pipe is unnamed, one-way, and generally used to transfer data from a parent process to a child process.

Named pipes can be one-way or duplex. Named pipes will work between processes on the same computer as well as between processes across the network.

Following are some of the Win32 APIs that are used when working with Named Pipes:

  • CreateNamedPipe()
  • ConnectNamedPipe()
  • WaitNamedPipe()
  • DisconnectNamedPipe()
  • ReadFile()
  • WriteFile()
  • CloseHandle()

A Named Pipe name needs to be in the following format:

  • For named pipe server - \.\pipe\PipeName
  • For named pipe client - \ComputerName\pipe\PipeName

Source Code Of Client:

#include <Windows.h>
#include <stdlib.h>
#include <stdio.h>
#include <tchar.h>

/*
1. [CreateFile](http://baike.baidu.com/view/1288759.htm)
*/
LPTSTR g_szPipeName = _T("\\\\.\\Pipe\\MyNamedPipe");
#define BUFFER_SIZE 1024
#define ACK_MESG_REVE "Message received successfully"

int main(int argv,char* argc[],char* env[]){

    HANDLE hPipe;
    /*
    HANDLE WINAPI CreateFile(
    _In_ LPCTSTR lpFileName,//普通文件名或者設備文件名
    _In_ DWORD dwDesiredAccess, //訪問模式(寫/讀)
    _In_ DWORD dwShareMode,//共享模式
    _In_opt_ LPSECURITY_ATTRIBUTES lpSecurityAttributes, //指向安全屬性的指針
    _In_ DWORD dwCreationDisposition, //如何創建
    _In_ DWORD dwFlagsAndAttributes, //文件屬性
    _In_opt_ HANDLE hTemplateFile //用於複製文件句柄
    );
    */
    hPipe = CreateFile(g_szPipeName, 
        GENERIC_READ | GENERIC_WRITE, 
        0, 
        NULL, 
        OPEN_EXISTING,
        0, 
        NULL);

    if (INVALID_HANDLE_VALUE == hPipe){
        printf("\nError occurred while connecting to the server: %d",GetLastError());
        return  1;
    }
    else{
        printf("\nCreateFile() was successful.\n");

    }

    char szBuffer[BUFFER_SIZE];
    printf("\nEnter a message to be sent to the server\n");
    gets_s(szBuffer);
    DWORD cbBytes;

    BOOL bResult = WriteFile(hPipe, szBuffer, strlen(szBuffer) + 1, &cbBytes, NULL);
    if ((!bResult) || (strlen(szBuffer) + 1 != cbBytes)){
        printf("\n Error occurred while writing to the server: %d\n", GetLastError());
        CloseHandle(hPipe);
        return 1;
    }
    else{
        printf("\nWriteFile() was successful..\n");
    }

    bResult = ReadFile(hPipe, szBuffer, sizeof(szBuffer),&cbBytes, NULL);
    if ((!bResult) || (0 == cbBytes)){
        printf("\n Error occurred while reading from the server: %d\n", GetLastError());
        CloseHandle(hPipe);
        return 1;
    }
    else{
        printf("\nReadFile() was successful...\n");
    }
    printf("\nServer sent the following message:%s\n",szBuffer);
    CloseHandle(hPipe);
    system("pause");
    return 0;

}

Source Code Of Server:

#include <Windows.h>
#include <stdlib.h>
#include <stdio.h>
#include <tchar.h>

TCHAR g_szPipeName[] = _T("\\\\\.\\Pipe\\MyNamedPipe");

#define BUFFER_SIZE 1024
#define ACK_MESG_RECV "Message reveived successfully..."

int main(int argc, char* argv[], char* env[]){
    HANDLE hPipe;
    /**
    HANDLE WINAPI CreateNamedPipe(
    _In_     LPCTSTR               lpName,
    _In_     DWORD                 dwOpenMode,
    _In_     DWORD                 dwPipeMode,
    _In_     DWORD                 nMaxInstances,
    _In_     DWORD                 nOutBufferSize,
    _In_     DWORD                 nInBufferSize,
    _In_     DWORD                 nDefaultTimeOut,
    _In_opt_ LPSECURITY_ATTRIBUTES lpSecurityAttributes
    );
    CreateNamedPipe創建一個命名管道。返回的句柄由管道的服務器端使用
    說明
    返回值
    Long,如執行成功,返回管道的句柄。INVALID_HANDLE_VALUE表示失敗。會設置GetLastError
    參數表
    參數 類型及說明
    lpName String,指定管道名,採用的形式是:\\.\管道\管道名。最多可達256個字符的長度,而且不用區分大小寫。如果存在指定名字的一個管道,則創建那個管道的一個新實例
    dwOpenMode Long,下述常數組的一個組合
        下述常數之一(對於管道的所有實例都要一樣):
        PIPE_ACCESS_DUPLEX 管道是雙向的
        PIPE_ACCESS_INBOUND 數據從客戶端流到服務器端
        PIPE_ACCESS_OUTBOUND 數據從服務器端流到客戶端
        下述常數的任意組合
        FILE_FLAG_WRITE_THROUGH 在網絡中建立的字節型管道內,強迫數據在每次讀寫操作的時候通過網絡傳輸。否則傳輸就可能延遲
        FILE_FLAG_OVERLAPPED 允許(但不要求)用這個管道進行異步(重疊式)操作
        常數WRITE_DAC, WRITE_OWNER 和 ACCESS_ SYSTEM_SECURITY提供了附加的安全選項
    dwPipeMode Long,下述常數組的一個組合:
        下述常數之一(管道的所有實例都必須指定相同的常數)
        PIPE_TYPE_BYTE 數據作爲一個連續的字節數據流寫入管道
        PIPE_TYPE_MESSAGE 數據用數據塊(名爲“消息”或“報文”)的形式寫入管道
        下述常數之一:
        PIPE_READMODE_BYTE 數據以單獨字節的形式從管道中讀出
        PIPE_READMODE_MESSAGE 數據以名爲“消息”的數據塊形式從管道中讀出(要求指定PIPE_TYPE_MESSAGE)
        下述常數之一:
        PIPE_WAIT 同步操作在等待的時候掛起線程
        PIPE_NOWAIT(不推薦!) 同步操作立即返回。這樣可爲異步傳輸提供一種落後的實現方法,已由Win32的重疊式傳輸機制取代了
    nMaxInstances Long,這個管道能夠創建的最大實例數量。必須是1到常數PIPE_UNLIMITED_INSTANCES間的一個值。它對於管道的所有實例來說都應是相同的
    nOutBufferSize Long,建議的輸出緩衝區長度;零表示用默認設置
    nInBufferSize Long,建議的輸入緩衝區長度;零表示用默認設置
    nDefaultTimeOut Long,管道的默認等待超時。對一個管道的所有實例來說都應相同
    lpSecurityAttributes SECURITY_ATTRIBUTES,指定一個SECURITY_ATTRIBUTES結構,或者傳遞零值(將參數聲明爲ByVal As Long,並傳遞零值),以便使用不允許繼承的一個默認描述符
    */
    hPipe = CreateNamedPipe(
        g_szPipeName, 
        PIPE_ACCESS_DUPLEX, 
        PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT, 
        PIPE_UNLIMITED_INSTANCES,
        BUFFER_SIZE, 
        BUFFER_SIZE, 
        NMPWAIT_USE_DEFAULT_WAIT, 
        NULL);

    if (INVALID_HANDLE_VALUE == hPipe){
        printf("\n Error occurred while creating the pipe: %d\n",GetLastError());
        return 1;
    }
    else{
        printf("\nCreateNamedPipe() was successful.\n");
    }

    printf("\n Waiting for client connection...\n");
    /*
    BOOL WINAPI ConnectNamedPipe(
    _In_        HANDLE       hNamedPipe,
    _Inout_opt_ LPOVERLAPPED lpOverlapped
    );
    ConnectNamedPipe是指示一臺服務器等待下去,直至客戶機同一個命名管道連接。
    返回值
    Long,如lpOverlapped爲NULL,那麼:
        如管道已連接,就返回Ture(非零);如發生錯誤,或者管道已經連接,就返回零(GetLastError此時會返回ERROR_PIPE_CONNECTED)
        lpOverlapped有效,就返回零;如管道已經連接,GetLastError會返回ERROR_PIPE_CONNECTED;如重疊操作成功完成,就返回ERROR_IO_PENDING。在這兩種情況下,倘若一個客戶已關閉了管道,且服務器尚未用DisconnectNamedPipe函數同客戶斷開連接,那麼GetLastError都會返回ERROR_NO_DATA
    參數表
    參數 類型及說明
    hNamedPipe Long,管道的句柄
    lpOverlapped OVERLAPPED,如設爲NULL(傳遞ByVal As Long),表示將線程掛起,直到一個客戶同管道連接爲止。否則就立即返回;此時,如管道尚未連接,客戶同管道連接時就會觸發lpOverlapped結構中的事件對象。隨後,可用一個等待函數來監視連接
    */
    BOOL bClientConnected = ConnectNamedPipe(hPipe, NULL);
    if (FALSE == bClientConnected){
        printf("\n Error occurred while connecting to the client:%d\n",GetLastError());
        CloseHandle(hPipe);
        return 1;
    }
    {
        printf("\nConnectNamePipe() was successful...\n");
    }

    /*
    BOOL WINAPI GetNamedPipeClientProcessId(
        _In_  HANDLE Pipe,
        _Out_ PULONG ClientProcessId
    );

    */
    //Get NamedPipeClientProcessId 
    PULONG ClientProcessID=0;
    GetNamedPipeClientProcessId(hPipe, ClientProcessID);
    if (FALSE == GetLastError()){
        printf("\nCan not Require processid of NamedPipeClient...\n");
    }
    else{
        printf("\n Current Client Process ID equal %ld\n",ClientProcessID);
    }

    //Get NamedPipeClient ComputerName
    /*
    BOOL WINAPI GetNamedPipeClientComputerName(
      _In_  HANDLE Pipe,
      _Out_ LPTSTR ClientComputerName,
      _In_  ULONG  ClientComputerNameLength
    );
    */
    LPTSTR ClientComputerName=NULL;
    ULONG ClientComputerNameLength = 1024;
    GetNamedPipeClientComputerName(hPipe, ClientComputerName, ClientComputerNameLength);
    if (FALSE == GetLastError()){
        printf("\nCan not require Client ComputerName of NamedPipeClient\n");
    }
    else{
        printf("current Client Computer name of NamedPipe equal %s\n",ClientComputerName);
    }

    char szBuffer[BUFFER_SIZE];
    DWORD cbBytes;

    BOOL bResult = ReadFile(hPipe, szBuffer, sizeof(szBuffer), &cbBytes, NULL);
    if ((!bResult) || (0 == cbBytes)){
        printf("\n Error occurred while reading from the client:%d\n",GetLastError());
        CloseHandle(hPipe);
        return 1;
    }
    else{
        printf("\n ReadFile() was successfule...\n");
    }
    printf("\n Client sent the following message: %s\n", szBuffer);
    strcpy_s(szBuffer, ACK_MESG_RECV);

    bResult = WriteFile(hPipe, szBuffer, strlen(szBuffer) + 1, &cbBytes, NULL);
    if ((!bResult) || (strlen(szBuffer) + 1 != cbBytes)){
        printf("\n Error occurred while writing to the client: %d", GetLastError());
        CloseHandle(hPipe);
        return 1;
    }
    else{
        printf("\n WriteFile() was successful...\n");
    }
    CloseHandle(hPipe);
    system("pause");
    return 0;
}

Notes on Named Pipe:

  • The source code is platform dependent.
  • A named pipe is easy to use.
  • A named pipe works across the network.

進程間通信之WinSock實現

Windows Sockets is a protocol-independent interface. It takes advantage of the communication capabilities of the underlying protocols. In Windows Sockets 2, a socket handle can optionally be used as a file handle with the standard file I/O functions.

Windows Sockets are based on the sockets first popularized by Berkeley Software Distribution (BSD). An application that uses Windows Sockets can communicate with other socket implementation on other types of systems. However, not all transport service providers support all available options.

Key Point: Windows Sockets is a protocol-independent interface capable of supporting current and emerging networking capabilities.


此程序Client和Server都必須包含ws2_32.lib


WinSock provides very high level networking capabilities. It supports TCP/IP (the most widely used protocol), along with many other protocols – AppleTalk, DECNet, IPX/SPX etc.

WinSock supports Berkeley sockets, along with many other Windows specific extensions.

Following are some of the WinSock calls:

  • socket()
  • bind()
  • listen()
  • accept()
  • connect()
  • send()
  • recv()

Source Code of Server:

#include <WinSock2.h>
#include <stdio.h>
#include <stdlib.h>
#pragma comment(lib,"ws2_32.lib")

#define ACK_MESG_RECV "Message received successfully"
int main(int argc, char* argv[], char* env[]){

    WSADATA wsaData;
    int nResult;
    nResult = WSAStartup(MAKEWORD(2, 2), &wsaData);
    if (NO_ERROR != nResult){
        printf("\n Error occurred while executing WSAStartup()...");
        return 1;
    }
    else{
        printf("\nWSAStartup() was successful...\n");
    }
    SOCKET listensocket, remotesocket;
    int port_no, client_length;
    char szBuffer[256];
    struct sockaddr_in ServerAddress, ClientAddress;
    listensocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
    if (INVALID_SOCKET == listensocket){
        printf("\nError occurred while opening socket: %ld.\n",WSAGetLastError());
        WSACleanup();
        return 0;
    }
    else{
        printf("\n socket() was successful...\n");
    }
    ZeroMemory((char*)&ServerAddress, sizeof(ServerAddress));
    port_no = atoi("4455");

    ServerAddress.sin_family = AF_INET;
    ServerAddress.sin_addr.S_un.S_addr = INADDR_ANY;
    ServerAddress.sin_port = htons(port_no);

    if (SOCKET_ERROR == bind(listensocket, (struct sockaddr*)&ServerAddress, sizeof(ServerAddress))){
        closesocket(listensocket);
        printf("\nError occurred while binding...\n");
        WSACleanup();
        return 0;
    }
    else{
        printf("bind() was successful..\n");
    }

    if (SOCKET_ERROR == listen(listensocket, SOMAXCONN)){
        closesocket(listensocket);
        printf("\n Error occurred while listening...\n");
        WSACleanup();
        return 0;
    }
    else{
        printf("\nlisten() was successful...\n");
    }
    client_length = sizeof(ClientAddress);

    remotesocket = accept(listensocket, (struct sockaddr *)&ClientAddress, &client_length);

    if (INVALID_SOCKET == remotesocket){
        closesocket(listensocket);
        printf("\nError occurred while accepting socket:%ld..\n", WSAGetLastError());
        WSACleanup();
        return 0;
    }
    else{
        printf("\naccept() was successful...\n");
    }

    printf("\n Client connected from :%s\n", inet_ntoa(ClientAddress.sin_addr));

    ZeroMemory(szBuffer, 256);

    int nBytesSent;
    int nBytesRecv;

    nBytesRecv = recv(remotesocket, szBuffer, 255, 0);
    if (SOCKET_ERROR == nBytesRecv){
        closesocket(listensocket);
        closesocket(remotesocket);
        printf("\nError occurred while receiving from socket...\n");
        WSACleanup();
        return 1;
    }
    else{
        printf("\nrecv() was successful...\n");
    }
    printf("\nThe following message was received:%s\n", szBuffer);
    nBytesSent = send(remotesocket, ACK_MESG_RECV, strlen(ACK_MESG_RECV), 0);
    if (SOCKET_ERROR == nBytesSent){
        closesocket(listensocket);
        closesocket(remotesocket);
        printf("\nError occurred while writing to socket.\n");
        WSACleanup();
        return 0;
    }
    else{
        printf("\nsend() was successful...\n");
    }

    closesocket(listensocket);
    closesocket(remotesocket);
    WSACleanup();
    system("pause");
    return 0;
}

Source Code of Client:

//#define _WINSOCK_DEPRECATED_NO_WARNINGS
#include <WinSock2.h>
#include <conio.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#pragma comment(lib, "ws2_32.lib")
/*
*/
int main(int argc, char* argv[], char* env[]){

    WSADATA wsaData;
    /*
    WSAStartup,是Windows Sockets Asynchronous的啓動命令、Windows下的網絡編程接口軟件 Winsock1 或 Winsock2 裏面的一個命令。
    int WSAStartup ( WORD wVersionRequested, LPWSADATA lpWSAData );
    ⑴ wVersionRequested:一個WORD(雙字節)型數值,在最高版本的Windows Sockets支持調用者使用,高階字節指定小版本(修訂本)號,低位字節指定主版本號。
    ⑵lpWSAData 指向WSADATA數據結構的指針,用來接收Windows Sockets實現的細節。
    WindowsSockets API提供的調用方可使用的最高版本號。高位字節指出副版本(修正)號,低位字節指明主版本號。

    本函數必須是應用程序或DLL調用的第一個Windows Sockets函數。它允許應用程序或DLL指明Windows Sockets API的版本號及獲得特定Windows Sockets實現的細節。應用程序或DLL只能在一次成功的WSAStartup()調用之後才能調用進一步的Windows Sockets API函數。
    返回值
    0 成功。
    否則返回下列的錯誤代碼之一。注意通常依靠應用程序調用WSAGetLastError()機制獲得的錯誤代碼是不能使用的,因爲Windows Sockets DLL可能沒有建立“上一錯誤”信息儲存的客戶數據區域。
    關於Windows Sockets提供者的說明:
    每一個Windows Sockets應用程序必須在進行其它Windows Sockets API調用前進行WSAStartup()調用。這樣,本函數就可以用於初始化的目的。
    */
    int nResult = WSAStartup(MAKEWORD(2, 2), &wsaData);
    if (NO_ERROR != nResult){
        printf("\n Error occurred while executing WSAStartup()...");
        return 1;
    }
    else{
        printf("\nWSAStartup() successful...");
    }
    //客戶端的socket對象結構
    SOCKET clientsocket;
    //連接服務器的端口
    int port_no;
    //服務器的socket信息
    struct  sockaddr_in ServerAddress;
    //struct  hostent *Server;

    //輸入輸出緩衝區大小
    char szBuffer[256];

    //char* to int
    port_no = atoi("4455");
    /*
    socket()函數用於根據指定的地址族、數據類型和協議來分配一個套接口的描述字及其所用的資源。如果協議protocol未指定(等於0),則使用缺省的連接方式。
    對於使用一給定地址族的某一特定套接口,只支持一種協議。但地址族可設爲AF_UNSPEC(未指定),這樣的話協議參數就要指定了。協議號特定於進行通訊的“通訊域”。
    int socket( int af, int type, int protocol);
    af:一個地址描述。目前僅支持AF_INET格式,也就是說ARPA Internet地址格式。
    type:指定socket類型。新套接口的類型描述類型,如TCP(SOCK_STREAM)和UDP(SOCK_DGRAM)。常用的socket類型有,SOCK_STREAM、SOCK_DGRAM、SOCK_RAW、SOCK_PACKET、SOCK_SEQPACKET等等。
    protocol:顧名思義,就是指定協議。套接口所用的協議。如調用者不想指定,可用0。常用的協議有,IPPROTO_TCP、IPPROTO_UDP、IPPROTO_STCP、IPPROTO_TIPC等,它們分別對應TCP傳輸協議、UDP傳輸協議、STCP傳輸協議、TIPC傳輸協議。
    若無錯誤發生,socket()返回引用新套接口的描述字。否則的話,返回INVALID_SOCKET錯誤,應用程序可通過WSAGetLastError()獲取相應錯誤代碼。
    */
    clientsocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
    if (INVALID_SOCKET == clientsocket){
        printf("\n Error occurred while opening socket: %d\n", WSAGetLastError());
        WSACleanup();
        return 0;
    }
    else{
        printf("\n socket() successful.\n");
    }
    //int ret = getaddrinfo("127.0.0.1", "4455",)

    /*Server = gethostbyname("127.0.0.1");
    if (Server == NULL){
        closesocket(clientsocket);
        printf("\nError occurred no such host\n");
        WSACleanup();
        return 0;
    }
    else{
        printf("\nGethostbyname() was successful\n");
    }*/
    //清理緩衝區
    ZeroMemory((char*)&ServerAddress,sizeof(ServerAddress));
    /*
    socket_in成員屬性
    sin_family指代協議族,在socket編程中只能是AF_INET
    sin_port存儲端口號(使用網絡字節順序),在linux下,端口號的範圍0~65535,同時0~1024範圍的端口號已經被系統使用或保留。
    sin_addr存儲IP地址,使用in_addr這個數據結構
    sin_zero是爲了讓sockaddr與sockaddr_in兩個數據結構保持大小相同而保留的空字節。
    */
    ServerAddress.sin_family = AF_INET;
    ServerAddress.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");
    ServerAddress.sin_port = htons(port_no);
    //CopyMemory((char*)&ServerAddress.sin_addr.S_un.S_addr, (char*)Server->h_addr_list, Server->h_length);
    //ServerAddress.sin_port = htons(port_no);


    //if (SOCKET_ERROR == connect(clientsocket, reinterpret_cast<const struct sockaddr *>(&ServerAddress), sizeof(ServerAddress))){
    /*
    函數原型: int connect(int s, const struct sockaddr * name, int namelen);
    參數:
    s:標識一個未連接socket
    name:指向要連接套接字的sockaddr結構體的指針
    namelen:sockaddr結構體的字節長度
    若無錯誤發生,則connect()返回0。否則的話,返回SOCKET_ERROR錯誤,應用程序可通過WSAGetLastError()獲取相應錯誤代碼。
    */
    if (SOCKET_ERROR == connect(clientsocket, (SOCKADDR*)&ServerAddress, sizeof(SOCKADDR))){
        closesocket(clientsocket);
        printf("\nError occurred while connecting...");
        WSACleanup();
        return 1;
    }
    else{
        printf("\nconnect() successful...");
    }
    ZeroMemory(szBuffer, 256);
    printf("\nPlease enter message to be sent to server..\n");

    fflush(stdin);
    fgets(szBuffer, 256, stdin);

    int nBytesSent; //發送的字節大小
    int nBytesRecv; //接受的字節大小
    /*
    send()用於向一個已經連接的socket發送數據,如果無錯誤,返回值爲所發送數據的總數,否則返回SOCKET_ERROR。[1]  send也是一個英文單詞。
    向一個已連接的套接口發送數據。
    #include <winsock.h>
    int PASCAL FAR send( SOCKET s, const char FAR* buf, int len, int flags);
    s:一個用於標識已連接套接口的描述字。
    buf:包含待發送數據的緩衝區。
    len:緩衝區中數據的長度。
    flags:調用執行方式。

    若無錯誤發生,send()返回所發送數據的總數(請注意這個數字可能小於len中所規定的大小)。否則的話,返回SOCKET_ERROR錯誤,應用程序可通過WSAGetLastError()獲取相應錯誤代碼。
    */
    nBytesSent = send(clientsocket, szBuffer, strlen(szBuffer), 0);

    if (SOCKET_ERROR == nBytesSent){
        closesocket(clientsocket);
        printf("\nError occurred while writing to socket...");
        WSACleanup();
        return 0;
    }
    else{
        printf("\nsend() was successful...");
    }

    ZeroMemory(szBuffer, 256);
    /*
    函數原型int recv( _In_ SOCKET s, _Out_ char *buf, _In_ int len, _In_ int flags);
    返回值:
    若無錯誤發生,recv()返回讀入的字節數。如果連接已中止,返回0。如果發生錯誤,返回-1,應用程序可通過perror()獲取相應錯誤信息。
    */
    nBytesRecv = recv(clientsocket, szBuffer, 255, 0);
    if (SOCKET_ERROR == nBytesRecv){
        closesocket(clientsocket);
        printf("\n Error occurred while reading from socket\n");
        WSACleanup();
        return 0;
    }
    else{
        printf("\nrecv() was successful...\n");
    }

    printf("\n%s\n", szBuffer);
    /*
    本函數關閉一個套接口。更確切地說,它釋放套接口描述字s,以後對s的訪問均以WSAENOTSOCK錯誤返回。若本次爲對套接口的最後一次訪問,則相應的名字信息及數據隊列都將被釋放。
    關閉一個套接口。
    #include <winsock.h>
    int PASCAL FAR closesocket( SOCKET s);
    s:一個套接口的描述字。
    返回值:
    如無錯誤發生,則closesocket()返回0。否則的話,返回SOCKET_ERROR錯誤,應用程序可通過WSAGetLastError()獲取相應錯誤代碼。
    */
    closesocket(clientsocket);
    /*
    WSACleanup()的功能是 終止Winsock 2 DLL (Ws2_32.dll) 的使用.
    頭文件
    #include <Winsock2.h>
    引用庫
    #pragma comment(lib, "ws2_32.lib")
    靜態加入一個lib文件也就是庫文件ws2_32.lib文件,提供相關API的支持,否則需要動態載入ws2_32.dll。
    函數原型
    int PASCAL FAR WSACleanup (void);
    返回值
    操作成功返回值爲0;否則返回值爲SOCKET_ERROR,可以通過調用WSAGetLastError獲取錯誤代碼。
    在一個多線程的環境下,WSACleanup()中止了Windows Sockets在所有線程上的操作.
    */
    WSACleanup();

    system("pause");
    return 0;
}

Notes on WinSock:

  • Widely used, and works on the same computer as well as across networks. Moreover, it can be used across various platforms and protocols.

  • Using WinSock requires a knowledge of relatively advanced networking concepts.


進程間通信之郵路實現

Mailslots provide one-way communication. Any process that creates a mailslot is a mailslot server. Other processes, called mailslot clients, send messages to the mailslot server by writing a message to its mailslot. Incoming messages are always appended to the mailslot. The mailslot saves the messages until the mailslot server has read them. A process can be both a mailslot server and a mailslot client, so two-way communication is possible using multiple mailslots.

A mailslot client can send a message to a mailslot on its local computer, to a mailslot on another computer, or to all mailslots with the same name on all computers in a specified network domain. Messages broadcast to all mailslots on a domain can be no longer than 400 bytes, whereas messages sent to a single mailslot are limited only by the maximum message size specified by the mailslot server when it created the mailslot.

Key Point: Mailslots offer an easy way for applications to send and receive short messages. They also provide the ability to broadcast messages across all computers in a network domain.


Mailslot is used for one way inter-process communications. There is a Mailslot server which will be read-only; it will just read the client sent messages. The clients will be write-only clients, sending messages to the server. Mailslot messages can be of around 400 bytes only.

Mailslot can broadcast messages in a domain. If processes in a domain create a mailslot with the same name, then a message that is sent to that mailslot is sent to all of these processes.

Following are some of the Win32 APIs that are used when working with Mailslot:

  • CreateMailSlot()
  • GetMailslotInfo()
  • SetMailslotInfo()
  • ReadFile()
  • WriteFile()
  • CloseHandle()

A Mailslot name needs to be in the following format:

  • \ComputerName\mailslot[path]name
  • \DomainName\mailslot[path]name
  • \*\mailslot[path]name

Source Code Of Client:

#include <Windows.h>
#include <stdlib.h>
#include <stdio.h>
#include <tchar.h>
TCHAR g_szMailSlot[] = _T("\\\\.\\mailslot\\MyMailSlot");

#define MAX_BUFFER_SIZE 1024

int main(int argc, char* argv[], char* env[]){
    HANDLE hMailSlot;
    hMailSlot = CreateFile(g_szMailSlot, GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
    if (INVALID_HANDLE_VALUE == hMailSlot){
        printf("\nError occurred while executing CreateFile()...%ld\n", GetLastError());
        return 1;
    }
    else{
        printf("\nCreateFile() was successfule...\n");
    }

    char szBuffer[MAX_BUFFER_SIZE];
    DWORD cbBytes;
    printf("\nEnter a message to be sent to the server:");
    fflush(stdin);
    fgets(szBuffer, MAX_BUFFER_SIZE - 1, stdin);

    BOOL bResult = WriteFile(hMailSlot, szBuffer, strlen(szBuffer) + 1, &cbBytes, NULL);

    if((!bResult) || (strlen(szBuffer) + 1 != cbBytes)){
        printf("\nError occurred while writing to the server:%ld\n", GetLastError());
        CloseHandle(hMailSlot);
        return 1;
    }
    else{
        printf("\nWriteFile() was successful...\n");
    }
    CloseHandle(hMailSlot);
    system("pause");
    return 0;

}

Source Code Of Server:

#include <Windows.h>
#include <stdlib.h>
#include <stdio.h>
#include <tchar.h>

TCHAR g_szMailslot[] = _T("\\\\.\\mailslot\\MyMailSlot");
#define MAX_BUFFER_SIZE  1024

int main(int argc, char* argv[], char* env[]){
    HANDLE hMailSlot;
    /*
    HANDLE WINAPI CreateMailslot(
      _In_     LPCTSTR               lpName, //指定郵路的名字,採用的形式如下:\\.\郵路\[路徑\]郵路名
      _In_     DWORD                 nMaxMessageSize, //指定一個郵路消息的最大長度。零表示無限長。請注意,對於穿越一個網絡域到多個郵路的廣播消息,最大長度是400
      _In_     DWORD                 lReadTimeout,  //等待指定的數據時,用這個參數指定郵路使用的默認超時設置,以毫秒爲單位。零表示不等待。常數MAILSLOT_WAIT_FOREVER表示一直等到數據到達
      _In_opt_ LPSECURITY_ATTRIBUTES lpSecurityAttributes //指定一個結構,或傳遞零值(將參數聲明爲ByVal As Long,並傳遞零值),表示使用不允許繼承的默認描述符
    );
    */
    hMailSlot = CreateMailslot(g_szMailslot, MAX_BUFFER_SIZE, MAILSLOT_WAIT_FOREVER, NULL);
    if (INVALID_HANDLE_VALUE == hMailSlot){
        printf("\nError occurred while executing CreateMailslot()...\n");
        return 1;
    }
    else{
        printf("\nCreateMailslot() was successful...\n");
    }

    char szBuffer[MAX_BUFFER_SIZE];
    DWORD cbBytes;
    BOOL bResult;
    printf("\nWaiting for client connection...");

    while (TRUE){
        bResult = ReadFile(hMailSlot, szBuffer, MAX_BUFFER_SIZE - 1, &cbBytes, NULL);
        if ((!bResult) || (0 == cbBytes)){
            printf("\nError occurred while executing readfile() from the client:%d...\n",GetLastError());
            CloseHandle(hMailSlot);
            return 1;
        }
        else{
            printf("\nReadFile() was successful...\n");
        }
        printf("\nClient sent thefollowing message:%s\n", szBuffer);
    }
    CloseHandle(hMailSlot);
    system("pause");
    return 0;
}

Notes on Mailslot

  • Source code is platform dependent.
  • Mailslot provides one-way communication only.
  • Size of message is limited to around 400 bytes.
  • Mailslot supports broadcasting.
  • Works across a network.
  • Mailslot is easy to use.

Threads vs. processes

Threads differ from traditional multitasking operating system processes in that:

  • processes are typically independent, while threads exist as subsets of a process
  • processes carry considerably more state information than threads, whereas multiple threads within a process share process state as well as memory and other resources
  • processes have separate address spaces, whereas threads share their address space
  • processes interact only through system-provided inter-process communication mechanisms
  • context switching between threads in the same process is typically faster than context switching between processes.

線程間通信

線程基本概念

In computer science, a thread of execution is the smallest sequence of programmed instructions that can be managed independently by a scheduler, which is typically a part of the operating system. The implementation of threads and processes differs between operating systems, but in most cases a thread is a component of a process. Multiple threads can exist within one process, executing concurrently and sharing resources such as memory, while different processes do not share these resources. In particular, the threads of a process share its executable code and the values of its variables at any given time.
Systems with a single processor generally implement multithreading by time slicing: the central processing unit (CPU) switches between different software threads. This context switching generally happens very often and rapidly enough that users perceive the threads or tasks as running in parallel. On a multiprocessor or multi-core system, multiple threads can execute in parallel, with every processor or core executing a separate thread simultaneously; on a processor or core with hardware threads, separate software threads can also be executed concurrently by separate hardware threads.

Single threading

In computer programming, single threading is the processing of one command at a time. The opposite of single threading is multithreading. While it has been suggested that the term single threading is misleading, the term has been widely accepted within the functional programming community.

Multithreading

Multithreading is mainly found in multitasking operating systems. Multithreading is a widespread programming and execution model that allows multiple threads to exist within the context of one process. These threads share the process’s resources, but are able to execute independently. The threaded programming model provides developers with a useful abstraction of concurrent execution. Multithreading can also be applied to one process to enable parallel execution on a multiprocessing system.

線程通信方式

使隸屬於同一進程的各線程協調一致地工作稱爲線程的同步。MFC提供了多種同步對象,下面我們只介紹最常用的四種:

  • 臨界區(CCriticalSection)
  • 事件(CEvent)
  • 互斥量(CMutex)
  • 信號量(CSemaphore)

Reference

  1. gcc4.7編譯thread程序
  2. pin 從windows 到 linux
  3. Pin工具的介紹
  4. C++11 多線程
  5. C++多線程編程(四)線程的同步
  6. C++多線程編程(1)C++組件
  7. Inter-process communication
  8. Inter-thread communication in java
  9. Thread (computing)
  10. Multithreading_(computer_architecture)
  11. Communicating sequential processes
  12. Interprocess Communications
  13. Windows IPC
  14. Synchronization of multiple reader and writer processes using Win32 APIs
  15. Basic Guide of Interprocess Communication and Pipes
  16. 多進程與多線程(三)–多進程 or 多線程
  17. Windows 多進程通信API總結
  18. fget(str,n,fd)和 stdin stdout
  19. C語言文件操作之fgets()
  20. fgets
  21. LPTSTR
  22. WaitForMultipleObjects
  23. WaitForSingleObject
  24. MapViewOfFile
  25. CreateEvent
  26. sprintf
  27. Linux多線程編程實例
  28. Creating Named Shared Memory
  29. CreateFile
  30. CreateNamedPipe
  31. CreateNamedPipe function
  32. ConnectNamedPipe
  33. GetNamedPipeClientComputerName function
  34. 簡單的 C++ SOCKET編程 —基於TCP/IP協議(轉)
  35. WSAStartup
  36. socket()
  37. SOCKADDR_IN
  38. connect()
  39. send()
  40. recv()
  41. WSACleanup()
  42. closesocket()
  43. CreateMailslot function
  44. Interprocess Communications
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章