Timeline
Timeline
2025-11-01
init
This article introduces the basics of Linux system application programming, elaborates on the installation of the man manual and the topic classification of its chapters, and systematically discusses file I/O operations under Linux, with a focus on analyzing the usage, parameter flags, and return values of system call functions such as open(), close(), and read().
man
Installation
1 | sudo pacman -Sy man-pages |
This method installs the man-pages that match the current system’s glibc version.
You can also directly query the man-pages for various Ubuntu versions on the web.
Content
| Section | Topic Classification | Content Examples | Typical Uses |
|---|---|---|---|
| 1 | User Commands | ls(1),grep(1),man(1) | Common shell commands, executable programs |
| 2 | System Calls | open(2),read(2),fork(2) | System call interface provided by the kernel (C language level) |
| 3 | C Library Functions | printf(3),malloc(3),strcpy(3) | Standard C Library (libc) and Other Library Functions |
| 4 | Devices and Special Files | null(4),tty(4) | /devDevice File Interface Under |
| 5 | File Formats and Conventions | passwd(5),fstab(5) | Configuration File Format Description |
| 6 | Games | fortune(6) | Historical Legacy, Now Rarely Used |
| 7 | Concepts and Protocols (Miscellaneous / Conventions / Protocols) | signal(7),socket(7),regex(7) | Semantic or Systematic Documentation (Protocols, Macros, Standards, etc.) |
| 8 | System Administration Commands | mount(8),ifconfig(8),systemd(8) | Commands Used Only by Root or Administrators |
| 9 | Kernel Developer Interface (Kernel Developer Docs, Non-standard) | request_irq(9)(Included in Kernel Source Code) | Kernel Programming API (Only Appears in Kernel Source Documentation) |
Usage
1 | man 2 open |
I/O Operations in Linux
File I/O
open()
| Function | int open(const char *pathname, int flags) int open(const char *pathname, int flags, mode_t mode) |
|---|---|
| Header File | #include <sys/types.h>#include <sys/stat.h>#include <fcntl.h> |
| Parameterspathname | Path and Filename |
| Parametersflags | File open mode, can be set by bitwise OR of multiple flags |
| Parametersmode | Permission mask, sets executable, read, write permissions for different users and groups, expressed in octal; this parameter is optional |
| Return Value | If open() executes successfully, itreturns an int file descriptor, and returns -1 on error. |
| Function | Through a system call, you can open a file and return a file descriptor. |
Optional flags for the parameter flags:
O_CREAT
Automatically create the file if the file name to be opened does not exist.O_EXCL
Must be used together with O_CREAT to take effect; if the file exists, the open() call fails.O_RDONLY
Open the file in read-only mode.O_WRONLY
Open the file in write-only mode.O_RDWR
Open the file in read-write mode.O_APPEND
Open the file in append mode.O_NONBLOCK
Open in non-blocking mode.
close()
| Function | int close(int fd) |
|---|---|
| Header file | #include <unistd.h> |
| Parametersfd | File descriptor |
| Return value | Returns 0 on success; returns -1 on error. |
read()
| Function | ssize_t read(int fd, void *buf, size_t count) |
|---|---|
| Header file | #include <unistd.h> |
| Parameterfd | File descriptor to read from |
| Parameterbuf | Buffer to store the read content |
| Parametercount | Number of bytes to read each time |
| Return value | Return value greater than 0 indicates the number of bytes read; Equal to 0 in blocking mode indicates end of file or no data to read (EOF), and blocks; Equal to -1 indicates an error, or in non-blocking mode indicates no data to read. |
write()
| Function | ssize_t write(int fd, const void *buf, size_t count); |
|---|---|
| Header file | #include <unistd.h> |
| Parametersfd | File descriptor |
| Parametersbuf | Buffer, storing data to be written |
| Parameterscount | Number of bytes to write each time (originally ‘count’ is more accurately bytes) |
| Function | Read count bytes from the buf buffer and write to the file identified by fd |
| Return value | Greater than or equal to 0 indicates success, returns the number of bytes written; Returns -1 indicates an error |
Note that write permission is required when opening
lseek()
All open files have aCurrent file offset, hereinafter referred to as cfo. cfo is usually anon-negative integer, used to indicate the number of bytes from the beginning of the file to the current file position. Read and write operations typically start at cfo and increase cfo by the number of bytes read or written. When a file is opened, cfo is initialized to 0 unless O_APPEND is used. The lseek function can be used to change the file’s cfo.
| Item | Description |
|---|---|
| Function Definition | off_t lseek(int fd, off_t offset, int whence); |
| Header File | #include <sys/types.h>#include <unistd.h> |
| Parameterfd | File Descriptor |
| Parameteroff_t offset | Offset,in bytes,positive and negative indicate moving forward and backward respectively |
| Parameterwhence | Position Base, optionalSEEK_SET(beginning of file),SEEK_CUR(current pointer position),SEEK_END(end of file) |
| Function | Move the file read/write pointer; get the file length; expand the file space |
| Return Value | SuccessReturns the current offset (SEEK_CUR), returns -1 on failure |
Example:
Set the file position pointer to 100 (beginning + 100 bytes)
1
lseek(fd,100,SEEK_SET);
Set the file position to the end of the file
1
lseek(fd,0,SEEK_END);
Determine the current file position
1
lseek(fd,0,SEEK_CUR);
access()
1 |
|
| Item | Content |
|---|---|
| Header file | #include <unistd.h> |
| Function Prototype | int access(const char *path, int amode); |
| Purpose | Check the specified pathpathFor the calling process’s**real user ID (real UID) and group ID (real GID)**whether it is accessible (e.g., readable, writable, executable, or exists). |
| Parameters | path: The file path to check.amode: The access mode to check, one of the following constants or their bitwise OR:F_OK: Whether the file existsR_OK: Whether it is readableW_OK: Whether it is writableX_OK: Whether it is executable |
| Return Value | Returns on success0; returns on failure-1and setserrno。 |
| common errno | EACCES: insufficient permissionsENOENT: file does not existENOTDIR: a component of the path is not a directoryEROFS: writing to a read-only file systemELOOP: too many symbolic linksENAMETOOLONG: path too long |
| behavior description | - usesreal user ID and group IDto check permissions, not effective ID. - Ifamodeis a combination of multiple flags, they are checked separately. - Only checks access permissions, does not actually open the file. |
| notes / limitations | ⚠️ Not recommended due toTOCTTOU (time-of-check-to-time-of-use) race condition: the file may have been modified after permission check. 👉 Safer approach: directly attempt the operation (e.g., open()) and catch errors. |
| Related functions | faccessat()(safer, can specify directory fd)chmod()、fstat() |
fnctl()
Operate on file descriptors
| Item | Description |
|---|---|
| Function definition | int fcntl(int fd, int cmd, … /* arg */ ); |
| Header file | #include <unistd.h>#include <fcntl.h> |
| Parameter fd | Thefile descriptor to operate on |
| Parameter cmd | Control command to execute (see table below) |
| Parameter arg(Optional) | For different cmd, the type of arg varies; it can be int, struct flock*, etc. |
| Function | Controls file descriptors, including: • Duplicate FD (F_DUPFD) • Set/Get FD flags (F_GETFD / F_SETFD) • Set/Get file status flags (F_GETFL / F_SETFL) • File locking (F_SETLK / F_SETLKW) |
| Return value | • On success: returns a value depending on cmd • On failure: returns**-1**, and sets errno |
Common CMD commands
| cmd name | Meaning | arg type | Return value |
|---|---|---|---|
| F_DUPFD | Duplicate file descriptor (≥ arg) | int | Return new fd |
| F_GETFD | Get FD flags (e.g., FD_CLOEXEC) | None | Return flags |
| F_SETFD | Set FD flags | int | 0 |
| F_GETFL | Get file status flags (O_NONBLOCK/O_APPEND, etc.) | None | Return flags |
| F_SETFL | Set file status flags (commonly used to set O_NONBLOCK) | int | 0 |
| F_SETLK | Set file lock (non-blocking) | struct flock* | Success 0, failure -1 |
| F_SETLKW | Set file lock (blocking) | struct flock* | Success 0 |
| F_GETLK | Test file lock status | struct flock* | 0 |
ioctl()
| Item | Description |
|---|---|
| Function definition | int ioctl(int fd, unsigned long request, … /* arg */ ); |
| Header file | #include <sys/ioctl.h>(May require device-specific header files, such aslinux/ioctl.h) |
| Parameter fd | Opened device file descriptor (e.g.,/dev/...) |
| Parameter request | IO control command (usually constructed via_IO,_IOR,_IOW,_IOWRand other macros) |
| Parameter arg(Optional) | Data associated with the request command, can beint*,void*,struct *etc. |
| Function | Execute control commands on the device driver (non-data read/write type), used for configuring hardware, obtaining status, sending control instructions, etc. |
| Return value | Success: usually0(may also return other positive values, depending on the request) Failure: returns**-1**, and sets errno |
Among the above three parameters, the most important is the second cmd parameter, which is of type unsigned int. To efficiently use the cmd parameter to pass more control information, an unsigned int cmd is split into 4 segments, each with its own meaning. The bit field split of unsigned int cmd is as follows:
1 | | 31 30 | 29 ................ 16 | 15 ...... 8 | 7 .......... 0 | |
- cmd[31:30]Transmission direction of data (args) (read/write)
- cmd[29:16]Size of data (args)
- cmd[15:8] **Type of command, can be understood as the key of the command,**generally an ASCII code (a character from 0-255, some characters are already occupied, and the sequence number segment of each character may be partially occupied)
- cmd[7:0]Command sequence number, is an 8-bit number (sequence number, between 0-255)
The cmd parameter is obtained from ioctl composite macro definitions. The four composite macro definitions are as follows:
- Define a command without parameters:
1 |
|
- Define a command where the application reads parameters from the driver:
1 |
|
- Define a command where the application writes parameters to the driver:
1 |
|
- Define a command where parameters are passed bidirectionally:
1 |
The macro definition parameter descriptions are as follows:
- type: The type of the command, generally an ASCII value. A driver typically uses one type
- nr: The sequence number under this command. A driver has multiple commands, generally with the same type but different sequence numbers
- size: The type of args
For example, the following code can be used to define three macros: one without parameters, one for writing parameters to the driver, and one for reading parameters from the driver:
1 |
Directory I/O
mkdir()
| Item | Description |
|---|---|
| Function | int mkdir(const char *pathname, mode_t mode) |
| Header file | #include <sys/stat.h>#include <sys/types.h> |
| Parameterpathname | Path and name of the directory to create |
| Parametermode | Permission mask, sets read, write, and execute permissions for user and group in octal; this parameter can be omitted |
| Return value | Returns 0 on success, -1 on error |
| Functionality | Create a directory |
opendir()/closedir()
| Function | Description |
|---|---|
| Function definition | **DIR opendir(const char name) |
| Header file | #include <sys/types.h>#include <dirent.h> |
| Parametersname | Pathname of the directory |
| Return value | On success, returns a directory stream (DIR*type)**; on failure, returnsNULL |
| Functionality | Open the specified directory and obtain a directory stream for traversing it |
| Function | Description |
|---|---|
| Function definition | int closedir(DIR *dirp) |
| Header file | #include <sys/types.h>#include <dirent.h> |
| Parametersdirp | Pointer to the directory stream to be closed |
| Functionality | Close the directory stream and release associated resources |
readdir()
1 | man 3 readdir |
| Item | Description |
|---|---|
| Function | struct dirent *readdir(DIR *dirp); int readdir_r(DIR *dirp, struct dirent *entry, struct dirent **result); |
| Header File | #include <dirent.h> |
| ParametersDIR *dirp | Directory stream pointer to read |
| Return Value | On success, returns a pointer to the directory entry (struct dirent*type), on failure returnsNULL |
| Functionality | Reads directory entries to traverse directory contents |
In the glibc implementation, the dirent structure is defined as follows:
1 | struct dirent { |
Note that the returned dirent is linked in a list form, meaning each read retrieves one directory entry, requiring a loop to traverse all entries.
Library
A library is an executable binary file containing compiled code。
Using libraries improves development efficiency. In Linux, there are static and dynamic libraries.
Static libraries are linked into the target code during program compilation. Therefore, the program no longer needs the static library at runtime. As a result, the compiled output is larger in size.Starts with ‘lib’ and ends with ‘.a’。
Dynamic libraries (also called shared libraries) are not linked into the target code during program compilation; instead, they are loaded when the program runs. Therefore, the program needs the dynamic library at runtime. As a result, the compiled output is smaller in size.Starts with ‘lib’ and ends with ‘.so’。
Static library
Steps to create a static library:
Write or prepare the library’s source code
Compile the source .c files to generate .o files
Use the ar command to create the static library
Test the library file
Example:
1 | # -c: Compile only, without linking, to generate .o object files |
Meaning of the ar command:
| Part | Explanation |
|---|---|
ar | The “archiver” tool, used for packaging.oFiles |
c | create: Create a new archive file (regardless of whether it exists) |
r | replace: Add the target file to the archive (replace if it already exists) |
libmylib.a | Output static library file name |
mylib.o | Object files to be added to the library |
How to use a static library
| Steps | Command example | Description |
|---|---|---|
| 1. Write the main program | main.c | Use functions provided by the library in the program |
| 2. Compile the main program and link the static library | gcc main.c -L. -lmylib -o main | -L.Specify the library file path-lSpecify the library name (remove the lib prefix and .a suffix) |
| 3. Run the program | ./main | The static library has been linked into the executable, no additional library files are needed |
Dynamic library
- Steps to create a dynamic library:
- Write or prepare the library’s source code
- Compile the source .c files to generate .o files
- Use the gcc command to create the dynamic library
- Test the library file
Example:
1 | gcc -c -fpic mylib.c -o mylib.o |
Step 1
| Option | Meaning |
|---|---|
-c | Compile only, do not link (generate.o) |
-fpic | GeneratePosition-independent code(Position Independent Code, PIC) |
mylib.c | Source file |
-o mylib.o | Output file name |
Step 2
| Option | Meaning |
|---|---|
-shared | Generate shared object (.sofile) instead of an executable |
-o libmylib.so | Specify output file |
mylib.o | Input object file |
The system will by default look for dynamic libraries in the /lib and /usr/lib directories. If the library we use is not there, an error will be reported.
First method:
Copy the generated dynamic library to /lib or /usr/lib, because the system will by default look in these two paths.Second method:
Add the path where our dynamic library is located to the environment variable. For example, if the path of our dynamic library is /home/test, we can add it like this, but this method is only valid in the currently set window.1
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/home/test/
The third method:
Modify the configuration file /etc/ld.so.conf under Ubuntu, we add the location of the dynamic library in this configuration file, and thenuse the command ldconfig to update the directory。
How to use dynamic libraries
| Steps | Command example | Description |
|---|---|---|
| 1. Write the main program | main.c | Use functions provided by the library in the program |
| 2. Compile the main program and link the dynamic library | gcc main.c -L. -lmylib -o main | Similar to static libraries,-lspecify the library name,-Lspecify the path |
| 3. Set the dynamic library path | export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/home/test/ | If the library is not in the system default path (/lib or /usr/lib), you need to set environment variables |
| 4. Run the program | ./main | The program loads dynamic libraries when running.soFile |
Process and Inter-Process Communication
Each process has a unique identifier, namely the process ID, abbreviated aspid
Methods of inter-process communication:
- Pipe communication: Named pipes, unnamed pipes
- Signal communication: Sending signals, receiving signals, handling signals
- IPC communication: Shared memory, message queues, semaphores
- Socket communication
Process basics
getpid()
| Project | getppid Function Description |
|---|---|
| Header File | #include <sys/types.h>#include <unistd.h> |
| Function | pid_t getppid(void); |
| Return Value | PID of the Parent Process |
| Functionality | Get the PID of the Current Process’s Parent |
fork()
| Project | fork Function Description |
|---|---|
| Header File | #include <unistd.h> |
| Function | pid_t fork(void); |
| Return Value | On successful call,the parent process returns the child’s PID, and the child process returns 0; Returns -1 on failure |
| Function | System call that creates a child process almost identical to the parent process, serving as one of the fundamental methods for achieving process concurrency |
exec
| Item | Description |
|---|---|
| Function | int execve(const char *filename, char *const argv[], char *const envp[]); |
| Header file | #include <unistd.h> |
| Parameterfilename | Pathname of the new program, specifying the location of the program to be loaded into the process space |
| Parameterargv [] | Command-line argument array,argv[0]the first element is the command name, subsequent elements are arguments |
| Parameterenvp [] | Environment variable array for the new program |
| Return value | Does not return on success; on failure, returns -1, and the error can be checked viaerrnocheck the error cause |
The following functions are all implemented based on execve
1 | int execl(const char *path, const char *arg, .../* (char |
| Function prototype | Core differences (path / arguments / environment variables) | Header file | Return value |
|---|---|---|---|
int execl(const char *path, const char *arg, .../* (char *) NULL */); | Absolute path, variable arguments, inherits environment | #include <unistd.h> | Does not return on success, returns -1 on failure |
int execlp(const char *file, const char *arg, .../* (char *) NULL */); | Automatically searches PATH, variable arguments, inherits environment | #include <unistd.h> | Does not return on success, returns -1 on failure |
int execle(const char *path, const char *arg, .../*, (char *) NULL, char * const envp[] */); | Absolute path, variable arguments, custom environment | #include <unistd.h> | Does not return on success, returns -1 on failure |
int execv(const char *path, char *const argv[]); | Absolute path, argument array, inherits environment | #include <unistd.h> | Does not return on success, returns -1 on failure |
int execvp(const char *file, char *const argv[]); | Auto search PATH, argument array, inherit environment | #include <unistd.h> | Returns nothing on success, returns -1 on failure |
int execvpe(const char *file, char *const argv[], char *const envp[]); | Auto search PATH, argument array, custom environment | #include <unistd.h> | Returns nothing on success, returns -1 on failure |
- Path rules: with
pfunctions (execlp, execvp, execvpe) can accept a filename, automatically searching in the systemPATHdirectories specified by environment variables for the program; withoutpfunctions (execl, execle, execv) require the absolute path of the program (e.g.,/bin/ls)。 - Argument passing: with
lfunctions (execl, execlp, execle) use variable arguments (...) to pass command-line arguments, and must end with(char*)NULL; withvfunctions (execv, execvp, execvpe) use a string arrayargvWhen passing parameters, the end of the array must beNULL。 - environment variable: with
efunctions (execle, execvpe) require manually passing an environment variable arrayenvp, customizing the runtime environment of the new program; withoutefunctions directly inherit the environment variables of the current process.
Example:
1 | if (pid == 0) |
pscommand
**Function:**List processes currently running in the system and their status.
Common parameters
| Parameter | Meaning |
|---|---|
aux | Display all processes of all users (a: show processes other than terminal, u: show user information, x: show processes without a controlling terminal) |
-ef | Similar to aux, display full format information |
-e | Display all processes |
-f | Full format display |
Example:
1 | $ ps aux |
Output includes fields:
| Field | Meaning |
|---|---|
| USER | User owning the process |
| PID | Process ID |
| %CPU | CPU usage |
| %MEM | Memory usage |
| VSZ | Virtual memory size (KB) |
| RSS | Resident memory size (KB) |
| STAT | Process status |
| COMMAND | Command name and arguments |
Process Status STAT
| Character | Description |
|---|---|
| D | Uninterruptible sleep (usually waiting for I/O) |
| R | Running or runnable (executing on CPU or waiting to be scheduled) |
| S | Sleeping (interruptible sleep, waiting for an event) |
| T | Stopped or traced (e.g.,Ctrl+Zstopped or being debugged) |
| Z | Zombie (child process terminated, but parent has not reaped it) |
| W | Out of memory, cannot page (rare) |
Additional Modifiers
| Character | Description |
|---|---|
< | High-priority process |
N | Low-priority process |
L | Locked in memory |
killCommand
**Function:**Send a signal to a process, usually to terminate it.
Example:
1 | $ kill -l |
Common Signals
| Signal | Description |
|---|---|
SIGTERM(15) | Terminate process, allowing cleanup; default signal |
SIGKILL(9) | Forcefully terminate process; cannot be caught, blocked, or ignored |
SIGSTOP(19) | Suspend process; can beSIGCONTResumed |
SIGCONT | Continue execution of a suspended process |
Orphan Process
Orphan Process:After the parent process ends, the child process has not yet ended, this child process is called an orphan process.
The orphan process will be adopted by the init process(in Ubuntu, it is /sbin/upstart), because some resources of the child process must be released by the parent process
Zombie process
Zombie process:After the child process ends, the parent process is still running, but the parent process does not release the process control block, this child process is called a zombie process
wait
The wait() function is generally used in the parent process to wait for and reclaim the resources of the child process, thereby preventing the generation of zombie processes.
| Item | Description |
|---|---|
| Function | pid_t wait(int *status) |
| Header file | #include <sys/wait.h> |
| Return value | On success, returns the PID of the recycled child process; on failure, returns -1 |
| Function and Interpretation | waitis a system call in Unix/Linux systems used by a parent process to wait for a child process to terminate. It blocks the parent process until a child process exits, then recycles the child’s resources and returns its PID.statusThe pointer is used to store the exit status of the child process, which can be parsed viaWIFEXITED、WEXITSTATUSmacros such as to determine whether the child process exited normally or terminated abnormally, and the specific exit code. This function is a key tool for process synchronization and resource reclamation, commonly used in scenarios where the parent process needs to wait for the child process to complete its task before continuing, such as in multi-process programming where the parent process uniformly manages the lifecycle of child processes. |
Two macro definitions related to the parameters of the wait function:
WIFEXITED(status): Ifthe child process exits normally, this macro evaluates to true
WEXITSTATUS(status): Ifthe child process exits normally, the value of this macro is the exit value of the child process。
Daemon
A daemon is a special type of process that runs in the background to perform specific system tasksMany daemons start at system boot and run until the system shuts down. Others start only when needed and automatically terminate after completing their tasks.
Daemons have no controlling terminal, so when certain events occur, whether they are routine informational reports or urgent messages requiring administrator attention, they need to be output in some way. The syslog function is the standard method for outputting such information; itsends the information to the syslogd daemon。
Basic Requirements of a Daemon:
- Must become a child of the init process (making the child process an orphan)
- Do not interact with the controlling terminal
Manually create a daemon process
Steps:
- First
fork(): Detach from parent process
1 | pid = fork(); |
- Purpose: Allow the child process to run in the background, so the parent process can immediately return to the shell.
- The child process is no longer the process group leader (in preparation for the next step
setsid).
- Call
setsid(): Create a new session
1 | setsid(); // Become the session leader of the new session and the leader of the new process group |
- Effect:
- Detach from the controlling terminal;
- No longer receive signals from the terminal (such as
Ctrl+C、SIGHUP); - Become a newsession leaderandprocess group leader。
⚠️ Must ensure that the process calling
setsid()isnot a process group leader, so the first stepfork()is necessary.
- Second
fork(): Ensure that the terminal cannot be reopened
1 | pid = fork(); |
- Purpose: The newly forked child processis no longer the session leader。
- According to POSIX regulations,only the session leader can reapply for a controlling terminal。
- Therefore, after the second
fork()the processcan never open a tty, completely becoming an “orphan”.
- Change working directory to root directory
/
1 | chdir("/"); |
- Reason: To prevent the daemon from occupying a mount point (such as
/home), causing the file system to be unmountable (umountfailure).
Optional: You can also switch to a specific log or data directory, but ensure that directory will not be unmounted.
- Close and redirect standard file descriptors (0, 1, 2)
1 | close(STDIN_FILENO); |
- Reason:
- Inherited from the parent process
stdin/stdout/stderrmay point to a terminal or pipe; - If not closed, it may cause resource leaks or unexpected output;
- Redirect to
/dev/nullcan avoid errors when library functions write (e.g.,printfwill not crash).
- Inherited from the parent process
- Set file permission mask
umask(0)
1 | umask(0); |
- Effect: Clear the file creation mask, so that the permissions of subsequently created files/directories are entirely specified by the program (e.g.,
0644、0755)。 - facilitates precise control over permissions of logs, PID files, etc.
Example:
1 |
|
Directly call daemon()
You can also directly call the daemon function:
1 |
|
Inter-process communication
Inter-process communication is also widely used, such as data transfer between background processes and GUI interfaces, sending signals to shut down, terminating running programs with Ctrl+C, etc.
Anonymous pipe
Anonymous pipes are the oldest form of inter-process communication, with the following two characteristics:
- Can only be used for data exchange between related processes, such as parent-child processes, sibling processes, descendant processes; no file node is visible in the directory, and read/write file descriptors are stored in an int array.
- **Data can only be transmitted in one direction.**That is, after the pipe is created, one process can only perform read operations, and the other process can only perform write operations. The byte order read out is the same as the order written.
| Item | Description |
|---|---|
| Function | int pipe(int pipefd[2]) |
| Header file | #include <unistd.h> |
| Parameter pipefd [2] | Integer array,pipefd[0]is the read-end file descriptor,pipefd[1]is the write-end file descriptor |
| Return value | Returns 0 on success, -1 on failure |
| Function and interpretation | pipeis a system call in Unix/Linux systems used to create unnamed pipes. Unnamed pipes are a method of inter-process communication, suitable only for bidirectional communication between processes with a kinship relationship (such as parent and child processes). After creation, one process can write data through the write end (pipefd[1]) and another process can read data through the read end (pipefd[0]) Read data to achieve one-way data transmission (if bidirectional is needed, two pipes must be created). Commonly used for command passing and data sharing between parent and child processes, for example, the parent process sends instructions to the child process through a pipe, and the child process returns the result to the parent process through the pipe after execution. |
Steps:
- Call pipe() to create an unnamed pipe;
- fork() creates a child process, one process reads using read(), and one process writes using write()。
Note:The unnamed pipe must be created before the fork() function!
1 |
|
Output:
1 | $ make |
Named pipe
| Item | Description |
|---|---|
| Function | int mkfifo(const char *pathname, mode_t mode) |
| Header file | #include <sys/types.h>#include <sys/stat.h> |
| Parameterspathname | The path and name of the named pipe, used to identify the pipe file to be created |
| Parametersmode | Permission mask, setting read and write permissions for user and group in octal (e.g.,0666) |
| Return Value | Returns 0 on success, -1 on failure |
| Function and Explanation | mkfifoIt is a function in Unix/Linux systems used to create named pipes. A named pipe is a special file that can be used for inter-process communication between unrelated processes. After creation, one process can write data to it like a regular file, and another process can read data from it, enabling bidirectional communication between processes. It is commonly used in scenarios where different programs exchange information, such as a server program and a client program passing commands and data through a named pipe. When using it, pay attention to permission settings to ensure that the communicating processes have appropriate read and write permissions for the pipe file. |
Usage Steps:
- Use mkfifo() to create a FIFO file descriptor.
- Open the pipe file descriptor.
- Perform unidirectional data transfer by reading and writing the file descriptor
Example
fifo_write.c
1 |
|
fifo_read.c
1 |
|
It can also be created using a command
1 | mkfifo fifo |
The pipe type file has a size of 0 and does not occupy disk space
Signal Communication
1 | [zhaohang@cyberboy /]$ kill -l |
| Signal Name | Description | Default Action |
|---|---|---|
| SIGHUP | Terminal hangup or controlling terminal closed (user logout) | Terminate |
| SIGINT | Terminal interrupt (Ctrl+C) | Terminate |
| SIGQUIT | Terminal quit (Ctrl+) | Terminate + core dump |
| SIGILL | Illegal instruction | Terminate + core dump |
| SIGTRAP | Debug breakpoint, single-step interrupt | Terminate + core dump |
| SIGABRT | abort()Call trace | Terminate + core dump |
| SIGBUS | Bus error (misaligned address access) | Terminate + core dump |
| SIGFPE | Arithmetic exception (e.g., division by zero) | Terminate + core dump |
| SIGKILL | Forced termination (cannot be caught/ignored) | Terminate |
| SIGUSR1 | User-defined signal 1 | Terminate |
| SIGSEGV | Segmentation fault (invalid memory access) | Terminate + core dump |
| SIGUSR2 | User-defined signal 2 | Terminate |
| SIGPIPE | Write to pipe with no reader | Terminate |
| SIGALRM | alarm()Expiration | Termination |
| SIGTERM | Termination signal (catchable) | Terminate |
| SIGCHLD | Child process exited or stopped | Ignore |
| SIGCONT | Continue running stopped process | Continue execution |
| SIGSTOP | Stop process (uncatchable) | Stop |
| SIGTSTP | User pause (Ctrl+Z) | Stop |
| SIGTTIN | Background process attempting read from terminal | Stop |
| SIGTTOU | Background process attempting write to terminal | Stop |
| SIGURG | Socket urgent data | Ignore |
| SIGXCPU | CPU time limit exceeded | Terminate + stack dump |
| SIGXFSZ | File size limit exceeded | Terminate + stack dump |
| SIGVTALRM | Virtual timer expired (ITIMER_VIRTUAL) | Terminate |
| SIGPROF | Profiling timer expired (ITIMER_PROF) | Terminate |
| SIGWINCH | Terminal window size changed | Ignore |
| SIGIO / SIGPOLL | Asynchronous I/O event (device readable/writable) | Ignore |
| SIGSYS | Illegal system call | Terminate + core dump |
| SIGPWR | Power failure (some system implementations) | Ignore or terminate |
| SIGSTKFLT | Coprocessor stack error (rarely used) | Terminate |
Send signal
kill()
| Item | Description |
|---|---|
| Function | int kill(pid_t pid, int sig) |
| Header file | #include <sys/types.h>#include <signal.h> |
| Parameter pid | - Greater than 0: send signal to process with PIDpidsend signal to the process- Equal to 0: send signal to processes in the same process group - Equal to -1: Send signal to all processes with process ID greater than 1, except itself - Less than -1: Send signal to all processes in the process group whose group ID equals the absolute value of pidthe absolute value |
| Parameter sig | The signal to send; when equal to 0, it is a null signal, commonly used for error checking |
| Return value | Returns 0 on success, -1 on error and setserrno |
| Function and interpretation | killis a function in Unix/Linux systems used to send signals to processes or process groups. Signals are a lightweight method of inter-process communication, used for operations such as interrupting, terminating, or querying the status of processes. For example, sendingSIGTERMsignal can gracefully terminate a process, sendingSIGKILLsignal can forcefully terminate a process. It is widely used in process management, program debugging, and other scenarios, serving as a key tool for asynchronous notification between processes. |
raise()
| Item | Description |
|---|---|
| Function | int raise(int sig) |
| Header file | #include <signal.h> |
| Parameter sig | Signal to be sent |
| Function and interpretation | raiseThe function is used to send a signal to the process itself, equivalent tokill(getpid(), sig). Signals are a mechanism for asynchronous communication between processes (including itself). This function can be used to implement logic such as self-interruption or self-termination of a process. For example, when a program detects an internal error, it usesraise(SIGABRT)to actively trigger an abnormal termination, facilitating debugging and resource cleanup. |
alarm()
| Item | Description |
|---|---|
| Function | unsigned int alarm(unsigned int seconds) |
| Header file | #include <unistd.h> |
| Parameter | Set alarm time (in seconds) |
| Function | After the set time expires, send theSIGALRMsignal to the process, with the default action being to terminate the process |
| Note | Each process can only have one activealarmtimer. If you need to use it again, you must re-register it |
Receiving Signals
Receiving Signals: If we want theprocess receiving the signal to be able to receive it, then this process must not stop. There are three methods to keep the process from stopping:
- while
- sleep
- pause
pause()
| Item | Description |
|---|---|
| Function | int pause(void) |
| Header File | #include <unistd.h> |
| Return Value | Returns -1 after the process is interrupted by a signal |
| Function and Interpretation | pauseThe function is used to suspend the process, putting it into a sleep state until a signal is received. It is commonly used in scenarios where a process needs to wait for an external event (such as a signal trigger) to continue execution, for example, implementing simple process synchronization or waiting for a specific signal to handle asynchronous events. Note that if the signal’s handling action is to terminate the process or ignore the signal,pausewill not return; only after the signal handler finishes execution,pausewill it return -1, at which point you can useerrnofor further analysis (usuallyerrnoisEINTRindicating interruption by a signal). |
Signal Handling
Signals are handled by the operating system,that is, signal processing occurs in kernel mode. Signals may not be processed immediately; at this point, they are stored in the signal table

From the above figure, it can be seen that there are three ways to handle signals:
- Default method (usually terminating the process),
- Ignore, performing no operation.
- Catch and handle by calling a signal handler (in the form of a callback function)
signal()
| Project | Description |
|---|---|
| Function | sighandler_t signal(int signum, sighandler_t handler);(can be simplified tosignal(参数1, 参数2);) |
| Header file | #include <unistd.h> |
| Parameter 1 (signum) | The signal to be handled. System signals can be viewed via the terminal commandkill -lview |
| Parameter 2 (handler) | Signal handling method: - Ignore signal: fill in SIG_IGN- System default handling: fill in SIG_DFL- Catch the signal and execute a custom function: must pass a function that conforms to sighandler_tfunction pointer of type (function definition format isvoid 函数名(int)) |
| return value | On success, returns the previous value of the signal handler registered for this signalhandlervalue; on failure, returnsSIG_ERR |
| Function and Explanation | signalThe function is used to modify the action taken by a process upon receiving a signal. It is a fundamental tool for signal handling in Unix/Linux systems. It allows ignoring, default handling, or custom capture logic for signals, such as capturing theSIGINTsignal (terminal interrupt signal) to achieve graceful program exit. It should be noted thatsignalbehavior differs across systems; for portability, it is recommended to use thesigactionfunction. |
Example
1 |
|
1 |
|
Shared Memory
Shared memory, as the name implies, allows two unrelated processes to access the same logical memory. It is a very efficient way for two running processes to share and transfer data. The memory shared between different processes is typically the same physical memory. Processes can attach the same physical memory to their own address spaces, and all processes can access the addresses in the shared memory. If one process writes data to the shared memory, the changes immediately affect any other process that can access the same shared memory.
Features:
- Fast speed, because shared memory does not require kernel control, so there are no system calls. Additionally, there is no process of copying data to the kernel, making it the fastest among the previous methods. It can be used for batch data transfer, such as images.
- No synchronization mechanism; it requires other tools provided by Linux for synchronization, typically using semaphores.
Steps to use shared memory:
- Call shmget() to create a shared memory segment ID,
- Call shmat() to attach the shared memory segment identified by the ID to the process’s virtual address space,
- Access the mapped address space added to the process, which can be read and written using I/O operations.
shmget()
Create or get shared memory
| Item | Description |
|---|---|
| Function | int shmget(key_t key, size_t size, int shmflg) |
| Parameter key | Generated byftokThe generated key identifier, used to uniquely identify IPC resources (shared memory) in the system |
| Parameter size | The size of the requested shared memory. The minimum unit for memory allocation by the operating system is a page (4k bytes), and it will be aligned upward to the page size. |
| Parameter shmflg | Control flags: - To create new shared memory: must combine with IPC_CREATandIPC_EXCL- To use existing shared memory: can use IPC_CREATor pass 0 directly |
| Return Value | Returns the shared memory identifier on success; returns -1 and sets an error code on failure |
| Function and Interpretation | shmgetis a system call in Unix/Linux systems used to create or obtain shared memory. Shared memory is the most efficient method of inter-process communication, allowing multiple processes to share data by mapping the same block of shared memory.shmgetis responsible for initializing the creation of shared memory or locating existing shared memory, providing the foundation for subsequentshmat(mapping),shmdt(unmapping),shmctl(control) operations. For example, when multiple processes collaborate to process large data, high-speed data transfer between processes can be achieved through shared memory. |
key == IPC_PRIVATE
- always creates a brand new, private shared memory segment;
- This segmentcan only be accessed by the current process and its child processes (inherited via fork);
- Other unrelated processesCannot find it via key(because
IPC_PRIVATEis not a global identifier); - Commonly used forinter-process communication between parent and child
key != IPC_PRIVATE(i.e., using a “global” key, such asftok()generated)
Whether a new segment is created at this point depends on whether two conditions aresimultaneously satisfied:
- does not yet exist in the systemthe shared memory segment corresponding to
key; shmflgcontains theIPC_CREATflag.
If both conditions are met →Create a new segment;
If the segment already exists →Return the ID of the existing segment(will not overwrite);
If not addedIPC_CREATand the segment does not exist → return -1, errorENOENT。
Example:
1 |
|
If created using IPC_PRIVATE, the key value is 0
View shared memory segments via command:
1 | $ ipcs -m |
-mindicates the operationshared memory segment, the following0isshmid(shared memory ID).
ftok()
Generate a unique key identifier for IPC (Inter-Process Communication) resources
| Item | Description |
|---|---|
| Function | key_t ftok(const char *pathname, int proj_id) |
| Header file | #include <sys/types.h>#include <sys/ipc.h> |
Parameterpathname | Path and name of the file, used as the base identifier for generating the unique key |
Parameterproj_id | Character identifier (usually a non-zero single-byte value), used to distinguish different keys generated from the same file |
| Return value | On success, returnskeyvalue; on failure, returns -1 |
| Function and interpretation | ftokThis function is used to generate a unique key identifier for IPC (Inter-Process Communication) resources, serving as the foundation for IPC mechanisms such as message queues, shared memory, and semaphores. It combines the file’s inode information withproj_idto generate a uniquekey, ensuring that different processes can use thiskeyto identify and access the same IPC resource. For example, when multiple processes use shared memory, they must first useftokto generate a consistentkey, then callshmgetto create or obtain shared memory. When using it, note that if the file path orproj_idchanges, the generatedkeywill also change, which may prevent processes from recognizing the shared resource. |
shmat()
Attach shared memory to the process’s address space
| Item | Description |
|---|---|
| Function | void *shmat(int shmid, const void *shmaddr, int shmflg) |
| Header file | #include <sys/types.h>#include <sys/shm.h> |
Parameterint shmid | Shared memory identifier, i.e., theshmgetreturn value of the function, used to identify the shared memory to be attached |
Parameterconst void *shmaddr | Mapping address, usually writeNULL, the system automatically completes the mapping of shared memory to the process address space |
Parameterint shmflg | access permission flag,0indicates readable and writable,SHM_RDONLYindicates read-only |
| Return Value | On success, returns the address of the shared memory mapped into the process; on failure, returns -1 ((void*)-1) |
| Function and Interpretation | shmatThe function is used to attach shared memory to the process’s address space, a key step in the shared memory usage process. After the process obtains the virtual address of the shared memory through this function, it can read and write the shared area like normal memory, achieving efficient data sharing between processes. For example, in multi-process collaborative tasks, data written by one process to shared memory can be read by other processes that have attached the same shared memory. When using it, note that after successful attachment, it must beshmdtto unmap, avoiding resource leaks; also pay attention to access permissions to ensure the process’s operations on shared memory comply withshmflgsettings. |
shmdt()
Removes the mapping of shared memory from the process address space, but does not delete the shared memory object in the kernel
| Project | Description |
|---|---|
| Function | int shmdt(const void *shmaddr) |
| Header File | #include <sys/types.h>#include <sys/shm.h> |
Parametersconst void *shmaddr | Address of shared memory mapped to the process (i.e.,shmatthe return value of the function) |
| Return Value | Returns 0 on success, -1 on failure |
| Functionality | Unmaps the shared memory from the process address space (detaches shared memory) |
| Note | shmdtOnly removes the mapping of shared memory from the process address space, does not delete the shared memory object in the kernel. To delete the shared memory in the kernel, call theshmctlfunction and specifyIPC_RMIDcommand. |
shmctl()
Performs control operations on shared memory, using differentcmdcommand, can achievequery, modification of shared memory attributes, and deletion of objects
| Item | Description |
|---|---|
| Function | int shmctl(int shmid, int cmd, struct shmid_ds *buf) |
| Header file | #include <sys/ipc.h>#include <sys/shm.h> |
Parameterint shmid | Shared memory identifier, used to specify the shared memory resource to operate on |
Parameterint cmd | Operation command: - IPC_STAT: Get shared memory attributes- IPC_SET: Set shared memory attributes- IPC_RMID: Delete shared memory object |
Parameterstruct shmid_ds *buf | Pointer to the structure used to store or set shared memory attributes, inIPC_STATandIPC_SETwhen used |
| Function and Interpretation | shmctlThe function is used to control shared memory operations and is a key tool for managing the lifecycle of shared memory. Through differentcmdcommands, it can query, modify attributes, and delete objects of shared memory. For example, when a process no longer needs shared memory, callingshmctl(shmid, IPC_RMID, NULL)can delete the shared memory object in the kernel, releasing system resources. This function ensures proper reclamation of shared memory resources, avoiding system overhead or conflicts caused by unreleased resources. |
Example
Parent and child processes communicate via shared memory.
1 |
|
There is no guarantee here that the parent process has finished writing when the child process reads the shared memory, so a pipe or semaphore is needed
Message Queue
Three types of IPCs
1 | [zhaohang@cyberboy /]$ ipcs |

The steps for application layer IPC communication are
Obtain a key value; the kernel maps the key to an IPC identifier. Common methods to obtain a key:
- Use the IPC_PRIVATE constant as the key value in the get call.
- Use ftok() to generate a key.
Execute the IPC get call to obtain an integer IPC identifier id from the key; each id represents an IPC object.
- Message queue: msgget()
- Shared memory: shmget()
- Semaphore: semget()
Access the IPC object via its id.
Characteristics of message queues:
- Sent messages are stored in a linked list, akin to a list; processes can add and retrieve messages from the corresponding ‘list’ by id.
- When receiving data, a process can retrieve data from the queue by type.
Steps for using message queues:
- Create key;
- msgget() creates (or opens) the message queue object id via key;
- Use msgsnd()/msgrcv() for sending and receiving;
- Delete the IPC object via msgctl();
After obtaining the id via msgget() call, the message queue can be used to access the IPC object. Common APIs for message queues are as follows:
msgget()
Used to obtain or create the unique identifier ID of the message queue
| Function | msgget |
|---|---|
| Function Prototype | int msgget(key_t key, int msgflg) |
| Header File | #include <sys/types.h>#include <sys/ipc.h>#include <sys/msg.h> |
| Parameters | -key: Key value associated with the message queue- msgflg: Access permissions: -IPC_CREAT: Create if the message queue does not exist -IPC_EXCL: Used withIPC_CREATtogether, if the message queue already exists, an error is reported - permission bits (e.g.,0666): Specifies the access permissions for the created message queue. |
| Return Value | Returns the message queue ID on success, or -1 on failure. |
| Function and Explanation | Used to obtain or create a unique identifier for a message queue, which is the initialization step of the message queue IPC mechanism. |
msgsnd()
| Function | msgsnd |
|---|---|
| Function Prototype | int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg) |
| Header File | #include <sys/types.h>#include <sys/ipc.h>#include <sys/msg.h> |
| Parameters | -msqid: Message queue ID- msgp: Pointer to the message- msgsz: Number of bytes in the message- msgflg: Send mode (0 for blocking,IPC_NOWAITnon-blocking) |
| Return Value | Returns 0 on success, -1 on failure |
| Function and Explanation | Used to send data to a message queue, supporting blocking/non-blocking modes. It is a core tool for inter-process message passing. |
msgctl()
| Function | msgctl |
|---|---|
| Function Prototype | int msgctl(int msqid, int cmd, struct msqid_ds *buf) |
| Header File | #include <sys/types.h>#include <sys/ipc.h>#include <sys/msg.h> |
| Parameters | -msqid: Message queue ID- cmd: Operation command (IPC_STAT/IPC_SET/IPC_RMID)- buf: Pointer to a structure for storing or setting attributes |
| Return Value | Returns 0 on success, -1 on failure |
| Function and Explanation | Used to query, modify, or delete attributes of a message queue. It is a key function for managing the lifecycle of a message queue. |
msgrcv()
| Project | Description |
|---|---|
| Function | ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp, int msgflg) |
Parametermsqid | IPC identifier of the message queue, used to specify the queue from which to receive messages |
Parametermsgp | Pointer to the message buffer, used to store the received message (the message must include type and data fields) |
Parametermsgsz | Size of the message data field (excluding the bytes of the message type) |
Parametermsgtyp | Type of message to receive, used to filter messages of a specific type |
Parametermsgflg | Bitmask that can combine multiple flags (e.g.,IPC_NOWAITindicates non-blocking reception) |
| Return Value | On success, returns the size of the received message data field; on error, returns -1 |
| Function and Interpretation | msgrcvis a function in Unix/Linux systems used to receive messages from a message queue. It supports filtering reception by message type, enabling asynchronous message interaction and categorized processing between processes. For example, in scenarios where multiple clients send different types of requests to a server, the server can usemsgtypto distinguish request types and process them separately. The reception mode can bemsgflgconfigured as blocking or non-blocking, flexibly adapting to different business needs. This function is a key part of implementing message consumption in the message queue IPC mechanism. |
Example
Write to the message queue:
1 |
|
Read from the message queue from the beginning
1 |
|
Run:
1 | $ ./msg_write.o |
Semaphore
To prevent a series of problems caused by multiple programs accessing a shared resource simultaneously, we need a method that can authorize access by generating and using tokens, allowing only one execution thread to access the critical section of code at any given time. A critical section refers to code that performs data updates and needs to be executed exclusively. Semaphores provide such an access mechanism, ensuring that only one thread accesses a critical section at a time. In other words, semaphores are used to coordinate process access to shared resources.
Semaphores can only perform two operations: wait and signal, i.e.,P(sv)andV(sv),
P(sv): If the value of sv is greater than zero, decrement it by 1; if its value is zero, suspend the execution of the process.
V(sv): If there are other processes suspended waiting for sv, resume one; if no process is suspended waiting for sv, increment it by 1.
semget()
| Function | semget |
|---|---|
| Function Prototype | int semget(key_t key, int nsems, int semflg) |
| Header File | #include <sys/types.h>#include <sys/ipc.h>#include <sys/sem.h> |
| Parameters | -key: Key value of the semaphore- nsems: Number of semaphores- semflg: Flags (e.g., creation/access permissions) |
| Return Value | Returns semaphore ID on success, -1 on failure |
| Function and Explanation | Used to create a new semaphore or obtain the ID of an existing semaphore; it is the initialization step of the semaphore IPC mechanism. |
semctl()
| Function | semctl |
|---|---|
| Function Prototype | int semctl(int semid, int semnum, int cmd, union semun arg) |
| Header File | #include <sys/types.h>#include <sys/ipc.h>#include <sys/sem.h> |
| Parameters | -semid: Semaphore ID -semnum: Semaphore number- cmd: Operation command (IPC_STAT/IPC_SET/IPC_RMID/SETVALetc.)- arg:union semunStructure for storing or setting semaphore attributes |
| Function and Interpretation | Used to query, modify, initialize, or delete semaphore attributes; it is a key function for semaphore lifecycle management. |
semop()
| Function | semop |
|---|---|
| Function prototype | int semop(int semid, struct sembuf *sops, size_t nsops) |
| Header file | #include <sys/types.h>#include <sys/ipc.h>#include <sys/sem.h> |
| Parameters | -semid: Semaphore ID- sops:struct sembufArray of structures, each element contains semaphore number, operation (sem_op: 1 for V operation, -1 for P operation, 0 for wait), operation mode (sem_flg: 0 means blocking,IPC_NOWAITnon-blocking)- nsops: number of semaphores to operate on |
| Function and Interpretation | Used to perform P (acquire resource) and V (release resource) operations on semaphores, enabling synchronization and mutual exclusion between processes. |
Example
1 |
|
