Fundamentals 31 min read

Master Linux Process Creation & IPC: System Calls, Queues, Shared Memory, Sockets, Pipes, Semaphores

This guide explains what a process is, how it differs from a thread, various ways to create and terminate processes in Linux, and provides detailed examples of inter‑process communication mechanisms—including message queues, shared memory, UNIX domain sockets, pipes, and semaphores—complete with C code samples.

Liangxu Linux
Liangxu Linux
Liangxu Linux
Master Linux Process Creation & IPC: System Calls, Queues, Shared Memory, Sockets, Pipes, Semaphores

Process and Thread Basics

A process is a running program with its own memory space and system resources; it is the basic unit of resource allocation. A thread is an execution unit within a process that shares the process’s memory and resources, and it is the basic unit of scheduling.

Difference between Process and Thread

Processes have independent address spaces and cannot directly share data. Threads share the same address space of their parent process.

Process Creation and Termination

Creating a Process

Using system() – simple but inefficient.

Using fork() – creates a child process.

Using the exec family – replaces the current process image with a new program.

#include <stdlib.h>
int main(void) {
    system("ls");
    printf("ls end
");
    return 0;
}
#include <sys/types.h>
#include <unistd.h>
#include <sys/wait.h>
int main(void) {
    pid_t res = fork();
    if (res == 0) {
        printf("I am child, pid = %d
", getpid());
        exit(EXIT_SUCCESS);
    } else if (res > 0) {
        int status;
        pid_t child = wait(&status);
        printf("Child %d terminated, status = %d
", child, status);
    } else {
        perror("fork");
        exit(EXIT_FAILURE);
    }
    return 0;
}
#include <unistd.h>
int main(void) {
    execl("/bin/ls", "ls", "-la", NULL);
    printf("ls end
");
    return 0;
}

Termination Methods

Return from main() (normal)

Call exit() (normal)

Call _exit() (normal)

Call abort() (abnormal)

Terminate via a signal (abnormal)

Inter‑Process Communication (IPC) in Linux

Message Queues

POSIX message queues are kernel‑managed priority queues. All processes that open the same queue can send and receive messages.

#include <fcntl.h>      /* O_* constants */
#include <sys/stat.h>   /* mode constants */
#include <mqueue.h>
Compile with -lrt .
mqd_t mq_open(const char *name, int oflag, mode_t mode, struct mq_attr *attr);
ssize_t mq_receive(mqd_t mqdes, char *msg_ptr, size_t msg_len, unsigned *msg_prio);
int mq_send(mqd_t mqdes, const char *msg_ptr, size_t msg_len, unsigned msg_prio);
int mq_close(mqd_t mqdes);
int mq_unlink(const char *name);

send.c

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <mqueue.h>
#define MQ_MSG_MAX_SIZE 512
#define MQ_MSG_MAX_ITEM 5
static mqd_t s_mq;
typedef struct { char buf[128]; int cnt; } msg_data_t;
void send_data(void) {
    static int cnt = 0;
    msg_data_t d = {0};
    cnt++;
    strcpy(d.buf, "hello");
    d.cnt = cnt;
    mq_send(s_mq, (char*)&d, sizeof(d), 0);
    printf("send msg = %s, cnt = %d
", d.buf, d.cnt);
}
int main(void) {
    struct mq_attr attr = {0};
    attr.mq_maxmsg = MQ_MSG_MAX_ITEM;
    attr.mq_msgsize = MQ_MSG_MAX_SIZE;
    s_mq = mq_open("/mq", O_CREAT|O_RDWR, 0777, &attr);
    for (size_t i = 0; i < 10; i++) { send_data(); sleep(1); }
    mq_close(s_mq);
    return 0;
}

recv.c

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <mqueue.h>
#define MQ_MSG_MAX_SIZE 512
typedef struct { char buf[128]; int cnt; } msg_data_t;
int main(void) {
    mqd_t mq = mq_open("/mq", O_RDONLY);
    if (mq == -1) { perror("mq_open"); return -1; }
    while (1) {
        msg_data_t d;
        unsigned prio;
        ssize_t n = mq_receive(mq, (char*)&d, MQ_MSG_MAX_SIZE, &prio);
        if (n == -1) { perror("mq_receive"); break; }
        printf("recv msg = %s, cnt = %d
", d.buf, d.cnt);
    }
    mq_close(mq);
    mq_unlink("/mq");
    return 0;
}

Compile and run:

gcc send.c -o send_process -lrt
gcc recv.c -o recv_process -lrt

Shared Memory

Shared memory maps a common physical region into the virtual address spaces of multiple processes, avoiding kernel‑user copies.

#include <sys/mman.h>
#include <sys/stat.h>
#include <unistd.h>
int shm_open(const char *name, int oflag, mode_t mode);
int shm_unlink(const char *name);
void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset);
int munmap(void *addr, size_t length);
int ftruncate(int fd, off_t length);
int fstat(int fd, struct stat *statbuf);

send.c

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/mman.h>
#define SHM_NAME "/shm"
int main(void) {
    int fd = shm_open(SHM_NAME, O_RDWR|O_CREAT, 0666);
    ftruncate(fd, 8*1024);
    struct stat sb;
    fstat(fd, &sb);
    char *ptr = mmap(NULL, sb.st_size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
    close(fd);
    const char *msg = "hello world";
    memcpy(ptr, msg, strlen(msg)+1);
    printf("pid %d, %s
", getpid(), ptr);
    munmap(ptr, sb.st_size);
    return 0;
}

recv.c

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/mman.h>
#define SHM_NAME "/shm"
int main(void) {
    int fd = shm_open(SHM_NAME, O_RDWR|O_CREAT, 0666);
    ftruncate(fd, 8*1024);
    struct stat sb;
    fstat(fd, &sb);
    char *ptr = mmap(NULL, sb.st_size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
    close(fd);
    printf("pid %d, %s
", getpid(), ptr);
    munmap(ptr, sb.st_size);
    shm_unlink(SHM_NAME);
    return 0;
}

Compile and run:

gcc send.c -o send_process -lrt
gcc recv.c -o recv_process -lrt

UNIX Domain Sockets

UNIX domain sockets use the file system as the address namespace, avoiding TCP/IP overhead.

#include <sys/socket.h>
#include <sys/un.h>

server.c

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <sys/un.h>
#define SERVER_PATH "/tmp/server"
int main(void) {
    int sfd = socket(AF_LOCAL, SOCK_STREAM, 0);
    unlink(SERVER_PATH);
    struct sockaddr_un addr = {0};
    addr.sun_family = AF_LOCAL;
    strncpy(addr.sun_path, SERVER_PATH, sizeof(addr.sun_path)-1);
    bind(sfd, (struct sockaddr *)&addr, sizeof(addr));
    listen(sfd, 10);
    int cfd = accept(sfd, NULL, NULL);
    while (1) {
        char buf[128] = {0};
        int n = read(cfd, buf, sizeof(buf));
        if (n <= 0) break;
        printf("recv: %s
", buf);
    }
    close(cfd);
    close(sfd);
    unlink(SERVER_PATH);
    return 0;
}

client.c

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <sys/un.h>
#define SERVER_PATH "/tmp/server"
#define CLIENT_PATH "/tmp/client"
int main(void) {
    int fd = socket(AF_LOCAL, SOCK_STREAM, 0);
    struct sockaddr_un client = {0};
    client.sun_family = AF_LOCAL;
    strncpy(client.sun_path, CLIENT_PATH, sizeof(client.sun_path)-1);
    unlink(CLIENT_PATH);
    bind(fd, (struct sockaddr *)&client, sizeof(client));
    struct sockaddr_un server = {0};
    server.sun_family = AF_LOCAL;
    strncpy(server.sun_path, SERVER_PATH, sizeof(server.sun_path)-1);
    if (connect(fd, (struct sockaddr *)&server, sizeof(server)) < 0) {
        perror("connect");
        exit(EXIT_FAILURE);
    }
    while (1) {
        char buf[128] = {0};
        if (scanf("%s", buf) == 1) {
            write(fd, buf, strlen(buf));
        }
    }
    close(fd);
    unlink(CLIENT_PATH);
    return 0;
}

Compile:

gcc server.c -o server_process
gcc client.c -o client_process

Pipes

Anonymous pipes provide half‑duplex communication between related processes.

#include <unistd.h>
int main(void) {
    int pipefd[2];
    pipe(pipefd);
    pid_t pid = fork();
    if (pid == 0) {
        char buf[128] = {0};
        read(pipefd[0], buf, sizeof(buf));
        printf("child recv: %s", buf);
    } else {
        const char *msg = "hello88888888
";
        write(pipefd[1], msg, strlen(msg));
    }
    return 0;
}

Named pipes (FIFOs) are identified by a pathname and can be used by any processes on the same host.

#include <fcntl.h>
#define FIFO_PATH "./fifo_file"
int main(void) {
    mkfifo(FIFO_PATH, 0664);
    int fd = open(FIFO_PATH, O_WRONLY);
    write(fd, "hello", 5);
    close(fd);
    return 0;
}

Semaphores

POSIX semaphores provide counting and binary synchronization primitives.

#include <semaphore.h>
sem_t *sem = sem_open("sem", O_CREAT, 0666, 1);
sem_wait(sem);   /* P operation */
sem_post(sem);   /* V operation */
sem_close(sem);
sem_unlink("sem");

Parent/Child Example

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <semaphore.h>
#define SEM_NAME "sem"
int main(void) {
    int val = 0;
    sem_t *sem = sem_open(SEM_NAME, O_CREAT, 0666, 1);
    if (!sem) { perror("sem_open"); exit(EXIT_FAILURE); }
    pid_t pid = fork();
    if (pid == 0) { /* child */
        for (int i = 0; i < 5; i++) {
            sem_wait(sem);
            sem_getvalue(sem, &val);
            printf("child P, val=%d
", val);
        }
        _exit(0);
    } else if (pid > 0) { /* parent */
        for (int i = 0; i < 5; i++) {
            sem_post(sem);
            sem_getvalue(sem, &val);
            printf("parent V, val=%d
", val);
            sleep(2);
        }
    }
    sem_close(sem);
    sem_unlink(SEM_NAME);
    return 0;
}

Compile with the pthread library:

gcc sem_example.c -o sem_example -lpthread

Summary of IPC Mechanisms

Message Queue: Kernel priority queue; processes enqueue and dequeue messages.

Shared Memory: Fastest method; multiple processes map the same physical memory.

UNIX Domain Socket: File‑system‑based sockets; no TCP/IP overhead.

Pipe: Kernel buffer; anonymous for related processes, named (FIFO) for any processes on the host.

Semaphore: Counter used for synchronization; supports named (inter‑process) and unnamed (intra‑process) variants.

References

https://xiaolincoding.com/os/4_process/process_commu.html

https://blog.csdn.net/sjsjnsjnn/article/details/125864580

https://huaweicloud.csdn.net/63564439d3efff3090b5cdec.html

https://blog.51cto.com/u_13456560/5822959

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

CLinuxMessage Queueshared memoryIPCprocesssystem callsSockets
Liangxu Linux
Written by

Liangxu Linux

Liangxu, a self‑taught IT professional now working as a Linux development engineer at a Fortune 500 multinational, shares extensive Linux knowledge—fundamentals, applications, tools, plus Git, databases, Raspberry Pi, etc. (Reply “Linux” to receive essential resources.)

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.