当前位置:首页 > 工具 > 正文内容

Linux/C++ 进程与线程核心概念

访客 工具 2026年7月6日 1

进程是程序在数据集合上的执行实例,是系统资源分配与调度的基本单位。

每个进程对应一个进程控制块(PCB),它是进程存在的唯一标志。PCB 存储了以下信息:

  • 进程描述信息:进程标识符、用户标识符
  • 控制与管理信息:进程状态、优先级
  • 资源清单:内存地址空间、打开文件列表、I/O 设备信息
  • CPU 上下文:进程切换时,CPU 寄存器的值保存在 PCB 中,以便恢复断点执行

进程的创建

使用 fork() 创建子进程,子进程会复制父进程的内存空间。

pid_t pid = fork();
if (pid < 0) {
    // 创建失败
} else if (pid == 0) {
    // 子进程
} else {
    // 父进程
}

getpid() 返回当前进程 PID,getppid() 返回父进程 PID。

执行新程序

execve() 系列函数用于替换当前进程映像,执行新程序。成功时不返回,失败返回 -1。

char *args[] = {"/bin/ls", "-l", NULL};
execve("/bin/ls", args, environ);

僵尸进程

子进程已结束但父进程未回收其状态信息,子进程变为僵尸进程。

危害:占用内核数据结构,消耗进程号,导致系统无法创建新进程。

解决方法:

  • 父进程调用 wait()waitpid() 阻塞等待
  • 注册 SIGCHLD 信号处理函数

孤儿进程

父进程先于子进程结束,子进程被 init 进程(PID=1)领养。

进程间通信

匿名管道

内核中的缓冲区,用于有亲缘关系的进程间通信。

int fd[2];
pipe(fd);
if (fork() == 0) {
    close(fd[1]);
    read(fd[0], buf, sizeof(buf));
} else {
    close(fd[0]);
    write(fd[1], "hello", 5);
}

有名管道

通过文件系统路径标识,可用于任意进程间通信。

mkfifo("/tmp/myfifo", 0664);
int fd = open("/tmp/myfifo", O_WRONLY);
write(fd, "data", 4);
close(fd);
unlink("/tmp/myfifo");

共享内存

映射一块内存区域,多个进程直接读写。

int shm_fd = shm_open("/myshm", O_CREAT | O_RDWR, 0664);
ftruncate(shm_fd, 1024);
void *ptr = mmap(NULL, 1024, PROT_READ | PROT_WRITE, MAP_SHARED, shm_fd, 0);
// 直接读写 ptr
munmap(ptr, 1024);
shm_unlink("/myshm");

消息队列

独立于发送和接收进程,由内核维护消息链表。

struct mq_attr attr = { .mq_maxmsg = 10, .mq_msgsize = 256 };
mqd_t mq = mq_open("/myqueue", O_RDWR | O_CREAT, 0664, &attr);
mq_send(mq, "msg", 3, 0);
char buf[256];
mq_receive(mq, buf, 256, NULL);
mq_close(mq);
mq_unlink("/myqueue");

信号

用于通知进程事件发生,不传递数据。

常用信号:

  • SIGINT (2): Ctrl+C
  • SIGKILL (9): 强制终止
  • SIGTERM (15): 终止信号
  • SIGCHLD (17): 子进程状态变化
signal(SIGINT, [](int sig) {
    cout << "捕获中断信号" << endl;
    exit(0);
});

进程终止

正常终止:returnexit()_exit() 等。异常终止:abort()、信号、线程取消。

exit() 会执行清理(刷新缓冲区、关闭文件),_exit() 不做清理直接退出。


线程

线程是进程内的执行单元,同一进程的线程共享代码段、数据段、文件资源,但各有独立栈和寄存器。

创建线程

Linux POSIX 线程:

pthread_t tid;
pthread_create(&tid, NULL, [](void*) -> void* {
    cout << "线程执行" << endl;
    return nullptr;
}, NULL);

C++11 std::thread:

#include <thread>
thread t1([](string s) { cout << s; }, "hello");
thread t2; // 无关联线程
t1.join(); // 等待结束
t2 = thread(foo);

等待与分离

join() 阻塞当前线程直到目标线程结束。detach() 分离线程,使其自行运行。

线程终止

POSIX:pthread_exit()pthread_cancel()。C++ 线程函数返回后自动终止。

同步机制

互斥锁

pthread_mutex_t mtx = PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_lock(&mtx);
// 临界区
pthread_mutex_unlock(&mtx);

C++ std::mutex + std::lock_guard 提供 RAII 风格。

mutex m;
{
    lock_guard<mutex> lock(m);
    // 自动加解锁
}

读写锁

允许多个读线程同时访问,写线程独占。

#include <shared_mutex>
shared_mutex rw;
{
    shared_lock<shared_mutex> read_lock(rw);
    // 读操作
}
{
    unique_lock<shared_mutex> write_lock(rw);
    // 写操作
}

自旋锁

忙等待,不阻塞线程。适用于短时间锁定。

atomic_flag flag = ATOMIC_FLAG_INIT;
void lock() { while(flag.test_and_set()); }
void unlock() { flag.clear(); }

条件变量

用于线程间等待某个条件满足。

condition_variable cv;
mutex cv_m;
bool ready = false;
// 等待线程
unique_lock<mutex> lk(cv_m);
cv.wait(lk, []{ return ready; });
// 通知线程
{
    lock_guard<mutex> lk(cv_m);
    ready = true;
}
cv.notify_one();

信号量

#include <semaphore.h>
sem_t sem;
sem_init(&sem, 0, 1);
sem_wait(&sem);
sem_post(&sem);
sem_destroy(&sem);

C++ 异步操作

std::future 与 std::async

future<int>> f = async(launch::async, [](int x) {
    this_thread::sleep_for(1s);
    return x * x;
}, 5);
cout << f.get() << endl; // 阻塞直到结果就绪

std::promise

手动设置异步结果。

promise<int> p;
future<int> f = p.get_future();
thread t([](promise<int> p) { p.set_value(42); }, move(p));
cout << f.get() << endl;
t.join();

std::packaged_task

封装可调用对象为异步任务。

packaged_task<int(int, int)> task([](int a, int b) { return a + b; });
future<int> f = task.get_future();
thread(move(task), 3, 4).detach();
cout << f.get() << endl;
标签: Linux

相关文章

Trojan服务器搭建与配置

一、整体架构(先对齐认知)Clash Meta (PC / iOS / Android)        ↓ TLS   Trojan Server (443)        ↓     InternetTrojan 的核心是: TLS + HTTPS 流量伪装 看起来像正常网站 非常适合...

Tailscale 的详细用法

Tailscale 是一种基于 WireGuard 协议 的 零配置 VPN(虚拟私有网络)服务,让设备之间能够 安全、加密地直接连接,就像它们在同一个本地网络一样。它的核心特点是 简单、安全、跨平台。Tailscale 非常适合 没有公网 IP、两台电脑不在同一局域网 的场景。 简单来说,Tailscale 是什么?Tailscale 是一款让你的各种设备(电脑、服务器、手机...

Clash Tun 模式 导致 爱快(iKuai SD-Wan)内网域名无法访问

一、Clash  DNS 配置dns:  enable: true  listen: 0.0.0.0:53  ipv6: true  enhanced-mode: redir-host  nameserver:    - 223.5.5.5    - 223.6.6.6iKuai 内网域名 ...

深入解析Node.js运行环境与异步I/O架构

深入解析Node.js运行环境与异步I/O架构

核心定义与价值Node.js本质上是一个JavaScript运行环境,而非编程语言或应用框架。它赋予了JavaScript脱离浏览器在服务端、命令行工具及网络应用中执行的能力。其核心意义在于:用单一语言打通前后端开发壁垒。基于事件驱动与非阻塞I/O的架构特性,Node.js在处理API网关、实时通信及微服务等I/O密集型场景时表现卓越,已成为现代后端工程的主流选择。浏览器沙箱限制1995年Java...

ADO.NET SQL参数化查询的最佳实践

在 ADO.NET 中执行 SQL 查询时,参数化查询是一种关键的安全措施和性能优化手段。它通过将 SQL 命令和用户提供的数据分开处理,有效防止了 SQL 注入攻击,并有助于数据库缓存执行计划。下面总结了几种常用的参数化查询方式。 1. 使用 SqlParameter 对象(推荐) 这是最推荐的参数化查询方式。通过显式创建 SqlParameter 对象,您可以精确控制参数的类...

基于ELK的日志集中化分析系统搭建

构建统一日志管理平台的必要性 在分布式架构中,各服务节点独立运行,日志分散存储于不同主机。传统通过命令行工具如grep、awk逐个检索日志的方式,在数据量庞大时效率极低,难以实现快速定位问题。为提升运维效率,需建立集中式日志处理体系,具备日志采集、传输、存储、分析与告警能力。 ELK技术栈核心组件解析 Elasticsearch:分布式搜索引擎,支持全文检索、实时数据分析和高可用集群部署,...

发表评论

访客

◎欢迎参与讨论,请在这里发表您的看法和观点。