Inter-Process Communication Mechanisms in C++

Inter-Process Communication (IPC) enables different processes to exchange data and coordinate operations within an operating system. Below are common IPC mechanisms along with implementation examples for both Windows and Linux platforms.

Fundamentals

  1. Pipe: A half-duplex communication channel typical used between related processes like parent-child. Data flows in one direction through a FIFO file descriptor.
  2. Named Pipe: A special file allowing unrelated processes to communicate via the filesystem. It has a path name and supports cross-process communication.
  3. Signal: An asynchronous notification mechanism that alerts a process of events such as termination (SIGINT). Process handlers can be registered using signal().
  4. Message Queue: Allows processes to send and receive messages via a queue. Each message has a type and is identified by a unique key.
  5. Shared Memory: Provides high-speed data sharing among multiple processes by mapping the same memory region into their address spaces. Requires synchronization to prevent race conditions.
  6. Semaphore: A counter-based synchronization primitive used to control access to shared resources. Processes perform P (wait) and V (signal) operations.
  7. Socket: Enables network communication but also supports local inter-process communication. Offers flexible communication over various protocols.

Windows IPC

Named Pipes

Server:

#include <windows.h>
#include <iostream>

int main() {
    HANDLE hPipe;
    char buffer[1024];
    DWORD bytesRead;

    hPipe = CreateNamedPipe(
        TEXT("\\\\.\\pipe\\MyPipe"),
        PIPE_ACCESS_INBOUND,
        PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT,
        1, 0, 0, NMPWAIT_USE_DEFAULT_WAIT, NULL);

    ConnectNamedPipe(hPipe, NULL);
    ReadFile(hPipe, buffer, sizeof(buffer), &bytesRead, NULL);
    std::cout << "Received: " << buffer << std::endl;

    CloseHandle(hPipe);
    return 0;
}

Client:

#include <windows.h>
#include <iostream>

int main() {
    HANDLE hPipe;
    const char* message = "Hello from client";
    DWORD bytesWritten;

    hPipe = CreateFile(
        TEXT("\\\\.\\pipe\\MyPipe"),
        GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL);

    WriteFile(hPipe, message, strlen(message) + 1, &bytesWritten, NULL);
    CloseHandle(hPipe);
    return 0;
}

Shared Memory

Writer:

#include <windows.h>
#include <iostream>

int main() {
    HANDLE hMapFile;
    LPCTSTR pBuf;

    hMapFile = CreateFileMapping(
        INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, 256, L"MySharedMem");

    pBuf = (LPTSTR)MapViewOfFile(hMapFile, FILE_MAP_ALL_ACCESS, 0, 0, 256);
    CopyMemory((PVOID)pBuf, "Data from writer", strlen("Data from writer") + 1);

    UnmapViewOfFile(pBuf);
    CloseHandle(hMapFile);
    return 0;
}

Reader:

#include <windows.h>
#include <iostream>

int main() {
    HANDLE hMapFile;
    LPCTSTR pBuf;

    hMapFile = OpenFileMapping(FILE_MAP_READ, FALSE, L"MySharedMem");
    pBuf = (LPTSTR)MapViewOfFile(hMapFile, FILE_MAP_READ, 0, 0, 256);
    std::cout << "Received: " << pBuf << std::endl;

    UnmapViewOfFile(pBuf);
    CloseHandle(hMapFile);
    return 0;
}

Message Queues

Sender:

#include <windows.h>
#include <iostream>

int main() {
    HANDLE hQueue;
    const char* message = "Hello from sender";

    hQueue = CreateMailslot(TEXT("\\\\.\\mailslot\\MySlot"), 0, MAILSLOT_WAIT_FOREVER, NULL);
    WriteFile(hQueue, message, strlen(message) + 1, NULL, NULL);
    CloseHandle(hQueue);
    return 0;
}

Receiver:

#include <windows.h>
#include <iostream>

int main() {
    HANDLE hQueue;
    char buffer[1024];
    DWORD bytesRead;

    hQueue = CreateFile(TEXT("\\\\.\\mailslot\\MySlot"), GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
    ReadFile(hQueue, buffer, sizeof(buffer), &bytesRead, NULL);
    std::cout << "Received: " << buffer << std::endl;
    CloseHandle(hQueue);
    return 0;
}

Semaphores

#include <windows.h>
#include <iostream>

int main() {
    HANDLE hSem = CreateSemaphore(NULL, 0, 1, L"MySemaphore");
    ReleaseSemaphore(hSem, 1, NULL);
    std::cout << "Semaphore signaled" << std::endl;
    CloseHandle(hSem);
    return 0;
}

Sockets

Server:

#include <winsock2.h>
#include <iostream>

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

int main() {
    WSADATA wsaData;
    SOCKET sListen, sClient;
    SOCKADDR_IN addr;
    char buffer[1024];

    WSAStartup(MAKEWORD(2, 2), &wsaData);
    sListen = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);

    addr.sin_family = AF_INET;
    addr.sin_addr.s_addr = htonl(INADDR_ANY);
    addr.sin_port = htons(8080);
    bind(sListen, (SOCKADDR*)&addr, sizeof(addr));
    listen(sListen, 5);

    sClient = accept(sListen, NULL, NULL);
    recv(sClient, buffer, sizeof(buffer), 0);
    std::cout << "Received: " << buffer << std::endl;

    closesocket(sClient);
    closesocket(sListen);
    WSACleanup();
    return 0;
}

Client:

#include <winsock2.h>
#include <iostream>

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

int main() {
    WSADATA wsaData;
    SOCKET sClient;
    SOCKADDR_IN addr;
    char* message = "Hello from client";

    WSAStartup(MAKEWORD(2, 2), &wsaData);
    sClient = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);

    addr.sin_family = AF_INET;
    addr.sin_addr.s_addr = inet_addr("127.0.0.1");
    addr.sin_port = htons(8080);
    connect(sClient, (SOCKADDR*)&addr, sizeof(addr));
    send(sClient, message, strlen(message), 0);

    closesocket(sClient);
    WSACleanup();
    return 0;
}

Linux IPC

Pipes

Parent:

#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main() {
    int pipefd[2];
    pid_t pid;
    char buffer[1024];

    pipe(pipefd);
    pid = fork();

    if (pid == 0) { // Child
        close(pipefd[1]);
        read(pipefd[0], buffer, sizeof(buffer));
        printf("Child received: %s\n", buffer);
        close(pipefd[0]);
        exit(0);
    } else { // Parent
        close(pipefd[0]);
        write(pipefd[1], "Hello from parent", 18);
        close(pipefd[1]);
        wait(NULL);
        exit(0);
    }
}

Shared Memory

Writer:

#include <sys/ipc.h>
#include <sys/shm.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main() {
    int shmid;
    char* shmaddr;
    key_t key = 1234;

    shmid = shmget(key, 1024, IPC_CREAT | 0666);
    shmaddr = shmat(shmid, NULL, 0);
    strcpy(shmaddr, "Data from writer");
    shmdt(shmaddr);
    return 0;
}

Reader:

#include <sys/ipc.h>
#include <sys/shm.h>
#include <stdio.h>
#include <stdlib.h>

int main() {
    int shmid;
    char* shmaddr;
    key_t key = 1234;

    shmid = shmget(key, 1024, 0666);
    shmaddr = shmat(shmid, NULL, 0);
    printf("Received: %s\n", shmaddr);
    shmdt(shmaddr);
    shmctl(shmid, IPC_RMID, NULL);
    return 0;
}

Message Queues

Sender:

#include <sys/msg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

struct msgbuf {
    long mtype;
    char mtext[1024];
};

int main() {
    int msgid;
    struct msgbuf msg;
    key_t key = 1234;

    msgid = msgget(key, IPC_CREAT | 0666);
    msg.mtype = 1;
    strcpy(msg.mtext, "Hello from sender");
    msgsnd(msgid, &msg, sizeof(msg), 0);
    return 0;
}

Receiver:

#include <sys/msg.h>
#include <stdio.h>
#include <stdlib.h>

struct msgbuf {
    long mtype;
    char mtext[1024];
};

int main() {
    int msgid;
    struct msgbuf msg;
    key_t key = 1234;

    msgid = msgget(key, 0666);
    msgrcv(msgid, &msg, sizeof(msg), 1, 0);
    printf("Received: %s\n", msg.mtext);
    msgctl(msgid, IPC_RMID, NULL);
    return 0;
}

Semaphores

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <stdio.h>
#include <stdlib.h>

int main() {
    int semid;
    struct sembuf op;

    semid = semget(IPC_PRIVATE, 1, 0666 | IPC_CREAT);
    semctl(semid, 0, SETVAL, 0);

    op.sem_num = 0;
    op.sem_op = 1;
    op.sem_flg = 0;
    semop(semid, &op, 1);
    printf("Semaphore signaled\n");
    semctl(semid, 0, IPC_RMID);
    return 0;
}

Sockets

Server:

#include <sys/socket.h>
#include <netinet/in.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main() {
    int sockfd, newsockfd;
    socklen_t clilen;
    char buffer[1024];
    struct sockaddr_in serv_addr, cli_addr;

    sockfd = socket(AF_INET, SOCK_STREAM, 0);
    serv_addr.sin_family = AF_INET;
    serv_addr.sin_addr.s_addr = INADDR_ANY;
    serv_addr.sin_port = htons(8080);
    bind(sockfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr));
    listen(sockfd, 5);

    clilen = sizeof(cli_addr);
    newsockfd = accept(sockfd, (struct sockaddr *)&cli_addr, &clilen);
    read(newsockfd, buffer, sizeof(buffer));
    printf("Received: %s\n", buffer);

    close(newsockfd);
    close(sockfd);
    return 0;
}

Client:

#include <sys/socket.h>
#include <netinet/in.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>

int main() {
    int sockfd;
    struct sockaddr_in serv_addr;
    char* message = "Hello from client";

    sockfd = socket(AF_INET, SOCK_STREAM, 0);
    serv_addr.sin_family = AF_INET;
    serv_addr.sin_port = htons(8080);
    inet_pton(AF_INET, "127.0.0.1", &serv_addr.sin_addr);

    connect(sockfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr));
    write(sockfd, message, strlen(message));
    close(sockfd);
    return 0;
}

Summary

Each IPC mechanism offers distinct advantages depending on use case:

  • Pipes: Simple unidirectional communication between related processes.
  • Shared Memory: Fastest method for large data exchange requiring synchronization.
  • Message Queues: Flexible message passing supporting multiple types.
  • Semaphores: Synchronization tool controlling access to shared resources.
  • Sockets: Versatile communication over networks or locally with protocol flexibility.

Tags: C++ inter-process communication IPC Windows Linux

Posted on Wed, 29 Jul 2026 17:10:24 +0000 by obesechicken13