在这里插入图片描述

💯枫亭湖区: 个人主页

🥰个人专栏: 《C++知识分享》   《Linux 入门到实践:零基础也能懂》

🌠 有善始者实繁,能克终者盖寡


分隔符

前言

根据我们前面所学习的知识:
Linux 内核是用 C 语言编写的,大部分底层头文件都是 C 风格的

本章带你学习并掌握Linux环境下进行C++系统编程时需要掌握的内核系统调用


一、核心系统调用

这是最基础的部分,几乎每个系统级程序都会用到

头文件 主要功能 常用函数/对象
<unistd.h> Linux 标准服务 read, write, close, fork, pipe, getpid
<fcntl.h> 文件控制 open, fcntl, O_CREAT, O_RDONLY
<sys/types.h> 基本系统数据类型 pid_t, size_t, mode_t
<sys/stat.h> 文件状态 stat, chmod, mkdir

1.1 <fcntl.h><unistd.h>:文件的打开与读写

#include <fcntl.h>    // open, O_WRONLY, O_CREAT
#include <unistd.h>	// write, close
#include <iostream>

int main(){
    // 1. 使用 open 打开或创建一个文件
    // O_WRONLY: 只写; O_CREAT: 不存在则创建; 0644: 设置权限
    int fd = open("example.txt", O_WRONLY | O_CREAT, 0644);
    
    if(fd = -1){
         perror("Open fail!!")
         return 1;
    }

    // 2. 使用 write 写入数据
    const char* text = "Hello Linux System Programming!";
    write(fd, text, 31);

    // 3. 使用 close 关闭文件描述符
    close(fd);

    cout << "文件写入并关闭成功!" << endl;
    return 0;
}

1.2 <sys/stat.h>:获取文件的“身份证”信息

如果你想知道一个文件有多大、什么时候修改的、是文件夹还是普通文件,就用这个头文件

#include <sys/stat.h>  // 包含系统状态结构 struct stat 和相关宏(如 S_ISDIR)
#include <iostream>    // 包含标准输入输出流(cout, endl)
#include <ctime>       // 包含 ctime 函数,用于处理时间转换

using namespace std;   // 引入标准命名空间,之后可以直接使用 cout, endl 等

int main() {
    // 定义一个结构体变量,用于接收内核返回的文件属性信息
    struct stat file_info;

    // --- 1. 获取文件状态 ---
    // stat() 会将 "example.txt" 的元数据填充到 file_info 结构体中
    if (stat("example.txt", &file_info) == 0) {
        
        // st_size 记录文件字节数
        cout << "文件大小: " << file_info.st_size << " 字节" << endl;
        
        // --- 2. 判定文件类型 ---
        // S_ISDIR 宏通过逻辑位运算检查 st_mode 字段
        if (S_ISDIR(file_info.st_mode)) {
            cout << "文件类型: 这是一个目录" << endl;
        } 
        else if (S_ISREG(file_info.st_mode)) {
            cout << "文件类型: 这是一个普通文件" << endl;
        }

        // --- 3. 时间戳转换 (进阶演示) ---
        // ctime() 将 st_mtime (秒数) 转换为人类可读的字符串(如 Mon Jun 1 21:15:00 2026)
        cout << "最后修改时间: " << ctime(&file_info.st_mtime); // ctime 自带换行

    } else {
        // 如果当前目录下没有 example.txt,代码会执行到这里
        cerr << "提示:未找到 example.txt,请先运行之前的写入示例。" << endl;
    }
    
    // --- 4. 创建新目录 ---
    // 0755 代表: 所有者(rwx=7), 组用户(r-x=5), 其他用户(r-x=5)
    if (mkdir("test_dir", 0755) == 0) {
        cout << "目录 'test_dir' 创建成功!" << endl;
    } else {
        // 报错的常见原因:目录已存在或权限不足
        cout << "目录创建失败,可能已存在。" << endl;
    }
    
    return 0;
}

1.3 <sys/types.h>:跨平台的类型保障

这个头文件更像是一个“翻译官”。它定义了如 pid_t(进程 ID 类型)、mode_t(权限模式类型)等。使用它能保证你的代码在不同的 Linux 架构下(如 32 位或 64 位)都能跑通

#include <sys/types.h>
#include <unistd.h>
#include <iostream>

int main() {
    // 使用 pid_t 而不是普通的 int,这更符合系统编程规范
    pid_t my_pid = getpid();
    pid_t parent_pid = getppid();

    std::cout << "当前进程 ID: " << my_pid << std::endl;
    std::cout << "父进程 ID: " << parent_pid << std::endl;

    return 0;
}

1.4 <unistd.h> 特色功能:创建子进程

除了读写文件,<unistd.h> 还有个绝活——fork(),它是 Linux 进程管理的灵魂

#include <unistd.h>
#include <iostream>

int main() {
    pid_t pid = fork();

    if (pid == 0) {
        // fork 返回 0,代表这里是子进程
        std::cout << "我是子进程,PID: " << getpid() << std::endl;
    } else if (pid > 0) {
        // fork 返回正数(子进程的 PID),代表这里是父进程
        std::cout << "我是父进程,我创建了子进程: " << pid << std::endl;
    }

    return 0;
}

总结一下区别:

  • <sys/types.h>:提供数据类型(如 pid_tsize_t
  • <fcntl.h>:提供文件操作标志(如 O_RDONLYO_NONBLOCK
  • <sys/stat.h>:提供文件属性查询(如文件大小、权限)
  • <unistd.h>:提供核心系统接口(如 readwriteforkpipe

二、多进程与信号处理

Linux 是多任务系统,处理进程间的交互至关重要

  • <sys/wait.h>:用于父进程等待子进程结束(如 wait, waitpid
  • <signal.h>:处理系统信号 在 C++ 中,通常需要处理 SIGINTCtrl+C)或 SIGPIPE
  • <sys/ipc.h> & <sys/shm.h>:共享内存交互,属于较老但强大的进程间通信方式

2.1 多进程:<sys/wait.h> + fork()

这段代码演示父进程如何创建子进程,并使用 wait() 优雅地为子进程回收资源,防止产生僵尸进程

#include <iostream>
#include <unistd.h>    // fork, sleep
#include <sys/wait.h>  // wait

using namespace std;

int main() {
    // 创建一个分身(子进程)
    pid_t pid = fork();

    if (pid == -1) {
        perror("fork 失败");
        return 1;
    }

    if (pid == 0) {
        // --- 这里是子进程的代码区 ---
        cout << "[子进程] 正在运行,我的 PID 是: " << getpid() << endl;
        sleep(2); // 模拟子进程干活 2 秒
        cout << "[子进程] 工作完成,准备退出。" << endl;
        return 88; // 退出码,可以传给父进程
    } else {
        // --- 这里是父进程的代码区 ---
        cout << "[父进程] 我在等待子进程 (PID: " << pid << ") 结束..." << endl;

        int status;
        // wait 函数会阻塞父进程,直到子进程结束
        // status 用于接收子进程的退出状态
        wait(&status); 

        if (WIFEXITED(status)) {
            cout << "[父进程] 检测到子进程正常退出,退出状态码: " << WEXITSTATUS(status) << endl;
        }
    }

    return 0;
}

2.2 信号处理:<signal.h>

信号是Linux发送给进程的异步通知
最常见的就是你按 Ctrl+C 时,系统会发送 SIGINT 信号

#include <iostream>
#include <signal.h> // 信号处理头文件
#include <unistd.h> // sleep

using namespace std;

// 这是一个信号处理函数(回调函数)
// 当指定的信号发生时,内核会自动跳过来执行这段代码
void my_handler(int sig_num) {
    cout << "\n[收到信号] 捕获到信号编号: " << sig_num << endl;
    cout << "[提示] 你是不是按了 Ctrl+C?但我还没想退出呢!" << endl;
    // 在实际开发中,这里通常用于平滑关闭数据库连接、保存日志等
}

int main() {
    // --- 注册信号处理器 ---
    // 告诉内核:如果有人发 SIGINT (Ctrl+C),请执行 my_handler
    signal(SIGINT, my_handler);

    cout << "程序已启动,正在循环运行。请尝试按 Ctrl+C 试试..." << endl;

    while (true) {
        cout << "工作中..." << endl;
        sleep(2);
    }

    return 0;
}

2.3 共享内存 (IPC):<sys/ipc.h> & <sys/shm.h>

共享内存允许两个完全独立的进程访问同一块物理内存,这是最快的进程间通信方式

由于代码逻辑较长(涉及创建、映射、读写、分离、删除),后面我们会展开讲解


三、网络编程 (Sockets)

Linux 的网络栈非常强大,主要涉及以下头文件:

  • <sys/socket.h>:核心套接字函数,如 socket, bind, listen, accept
  • <netinet/in.h>:定义互联网协议族(如 struct sockaddr_in
  • <arpa/inet.h>IP 地址转换工具(如 inet_pton, ntohs
  • <netdb.h>:域名解析(如 getaddrinfo

后面我们到 Linux系统编程的时候会讲解的


四、多线程编程

虽然 C++11 引入了原生的 <thread>,但在 Linux 系统编程中,底层往往是基于 POSIX Threads (Pthreads)


Linux 系统编程中,Pthreads 是多线程的标准实现 虽然现代 C++ 程序员习惯使用 <thread>,但在底层高性能服务器开发中,pthread 仍然是不可替代的,因为它提供了诸如线程分离、设置栈大小、设置调度策略、线程亲和性(绑定 CPU 核)等底层 API


4.1 核心头文件 <pthread.h>

要使用 Pthreads,必须包含这个头文件,并在编译时手动链接库:

g++ main.cpp -O main -lpthread

4.2 实操案例

#include <iostream>
#include <pthread.h> // 核心头文件
#include <unistd.h>  // sleep

using namespace std;

// 线程执行函数必须符合这个格式:void* 函数名(void*)
// 因为 void* 可以指向任何类型,这让我们可以传递任意参数
void* thread_work(void* arg) {
    // 将 void* 强制转回我们需要的类型
    char* msg = (char*)arg;
    
    for (int i = 0; i < 3; ++i) {
        cout << "[子线程] 收到消息: " << msg << ",正在处理 " << i << "..." << endl;
        sleep(1);
    }
    
    // 线程结束,可以返回一个结果
    return (void*)"子线程任务完成!";
}

int main() {
    pthread_t my_thread; // 线程的“身份证”变量
    const char* message = "Hello from Main!";

    // --- 1. 创建线程 ---
    /* 参数详解:
     * &my_thread : 存储新线程 ID
     * NULL       : 线程属性(通常用 NULL 表示默认属性)
     * thread_work: 线程要运行的函数名
     * (void*)message : 传给该函数的参数
     */
    if (pthread_create(&my_thread, NULL, thread_work, (void*)message) != 0) {
        cerr << "线程创建失败!" << endl;
        return 1;
    }

    cout << "[主线程] 子线程已启动,我先去喝杯咖啡..." << endl;

    // --- 2. 等待线程结束 (Join) ---
    /* 就像 wait() 等待子进程一样,pthread_join 会阻塞主线程,
     * 直到指定的线程运行结束。第二个参数用于接收返回值。
     */
    void* result;
    pthread_join(my_thread, &result);

    cout << "[主线程] 子线程返回信息: " << (char*)result << endl;
    cout << "[主线程] 程序退出。" << endl;

    return 0;
}

4.3 线程同步:互斥锁<pthread.h>

多线程是最怕乱的,两个线程同时改一个变量就会导致崩溃

  • pthread提供了互斥锁(Mutex):
pthread_mutex_t lock; // 定义一把锁

pthread_mutex_init(&lock, NULL); // 初始化锁
pthread_mutex_lock(&lock);       // 【加锁】— 进房间关门
// --- 临界区:操作共享资源 ---
pthread_mutex_unlock(&lock);     // 【解锁】— 出房间开门
pthread_mutex_destroy(&lock);    // 销毁锁

五、高性能 I/O 多路复用(自行了解)

这是开发高性能服务器(如 Web Server)的关键

  • <sys/select.h>:经典的 select 模型

  • <sys/poll.h>poll 模型

  • <sys/epoll.h>Linux 特有 在大规模并发连接下性能最强,是现代 Linux 网络引擎的核心


六、C 与 C++ 的转换

为了更符合 C++ 风格,建议优先使用带 c 前缀的头文件(如果标准库提供):

  • <cstdio> 代替 <stdio.h>
  • <cstring> 代替 <string.h>
  • <cerrno> 代替 <errno.h>(用于调试系统错误)

七、错误处理

Linux 系统调用失败通常返回 -1
你需要结合 <cerrno><cstring> 来获取可读的错误信息:

#include <iostream>
#include <cstring>
#include <cerrno>

if (write(fd, buf, size) == -1) {
    cerr << "Error: " << strerror(errno) << endl;
}


💻结尾— 核心连接协议

警告: 🌠🌠正在接入底层技术矩阵。如果你已成功破解学习中的逻辑断层,请执行以下指令序列以同步数据:🌠🌠


【📡】 建立深度链接: 关注本终端。在赛博丛林中深耕底层架构,从原始代码到进阶协议,同步见证每一次系统升级。

【⚡】 能量过载分发: 执行点赞操作。通过高带宽分发,让优质模组在信息流中高亮显示,赋予知识跨维度的传播力。

【💾】 离线缓存核心: 将本页加入收藏。把这些高频实战逻辑存入你的离线存储器,在遭遇系统崩溃或需要离线检索时,实现瞬时读取。

【💬】 协议加密解密:评论区留下你的散列码。分享你曾遭遇的代码冲突或系统漏洞(那些年踩过的坑),通过交互式编译共同绕过技术陷阱。

【🛰️】 信号频率投票: 通过投票发射你的选择。你的每一次点击都在重新定义矩阵的进化方向,决定下一个被全量拆解的技术节点。


在这里插入图片描述
在这里插入图片描述

更多推荐