当前位置: 首页 > news >正文

1.进程与线程:区别、通信方式、同步方式

目录

1. 进程 vs 线程:根本区别

2. 进程间通信(IPC)方式

3. 同步机制

4. 同步机制对比

5. 常见问题

Q1: 进程和线程的根本区别是什么?

Q2: 哪种IPC方式最快?为什么?

Q3: 互斥锁和信号量的区别?

Q4: 为什么条件变量需要配合互斥锁使用?

Q5: 什么是死锁?如何避免?

6. 实际应用建议

总结

1. 进程 vs 线程:根本区别

基本概念

  • 进程:程序的一次执行实例,是资源分配的基本单位

  • 线程:进程内的一个执行流,是CPU调度的基本单位

内存布局对比

进程内存布局:
+-----------------------+
|      栈区 (Stack)     | ← 每个线程有独立栈
+-----------------------+
|          ↓            |
|                       |
|         堆区 (Heap)    | ← 共享
+-----------------------+
|         ↑             |
|                       |
+-----------------------+
|   全局/静态数据区       | ← 共享
+-----------------------+
|       代码段          | ← 共享
+-----------------------+线程共享:代码段、数据段、堆、文件描述符、信号处理等
线程独有:栈、寄存器、程序计数器、线程局部存储

详细区别对比表

特性进程线程
资源分配操作系统分配独立资源共享进程资源
内存空间独立地址空间共享地址空间
创建开销大(需要分配资源)小(共享资源)
上下文切换开销大(需要切换页表等)开销小(只需切换寄存器)
通信方式复杂(IPC机制)简单(共享内存即可)
稳定性一个进程崩溃不影响其他进程一个线程崩溃会导致整个进程崩溃
数据共享需要显式IPC机制天然共享进程数据
独立性完全独立相互依赖

核心总结

  • 进程 是资源 ownership 的单位,为程序运行提供独立的沙盒环境。

  • 线程 是执行 schedule 的单位,是CPU真正调度和分派的基本单元,共享进程的资源以实现高效协作。

编程:

1. 创建进程 (使用 fork())

fork() 是Unix-like系统中创建新进程的主要方法。它会复制当前进程(父进程),创建一个几乎完全相同的子进程。

#include <iostream>
#include <unistd.h> // for fork(), getpid()
#include <sys/wait.h> // for wait()int main() {pid_t pid = fork(); // 创建子进程if (pid < 0) {// fork失败std::cerr << "Fork failed!" << std::endl;return 1;} else if (pid == 0) {// 这里是子进程的代码std::cout << "Hello from Child Process! My PID is: " << getpid() << std::endl;sleep(2); // 模拟子进程工作std::cout << "Child process exiting." << std::endl;} else {// 这里是父进程的代码 (pid > 0, pid是子进程的ID)std::cout << "Hello from Parent Process! I created a child with PID: " << pid << std::endl;wait(nullptr); // 等待子进程结束std::cout << "Parent process resumed after child exited." << std::endl;}return 0;
}
2. 创建线程 (使用 C++11 std::thread)

C++11提供了标准的线程库,跨平台且易于使用

#include <iostream>
#include <thread>
#include <chrono>// 线程要执行的函数
void thread_function(int id) {std::cout << "Thread " << id << " is starting..." << std::endl;std::this_thread::sleep_for(std::chrono::seconds(2)); // 模拟工作std::cout << "Thread " << id << " is finishing..." << std::endl;
}int main() {std::cout << "Main thread started." << std::endl;// 创建并启动两个线程std::thread t1(thread_function, 1);std::thread t2(thread_function, 2);// 等待线程结束t1.join();t2.join();std::cout << "Main thread finished." << std::endl;return 0;
}

2. 进程间通信(IPC)方式

由于进程地址空间独立,无法直接共享变量,因此需要操作系统提供特殊的机制来通信。

1. 管道 (Pipe)
  • 概念:一种半双工的通信方式,数据只能单向流动。通常用于有亲缘关系的进程(如父子进程)。

  • 原理:在内存中创建一个内核缓冲区,像一个队列。一个进程写,另一个进程读。

  • 类型

    • 匿名管道 (Anonymous Pipe):只能在父子进程间使用。

    • 命名管道 (Named Pipe / FIFO):提供了一个路径名与之关联,允许无亲缘关系的进程通信。

  • 特点:简单,但效率较低,容量有限,且通信是单向的。如果需要双向通信,需要建立两个管道。

2. 消息队列 (Message Queue)
  • 概念:存放在内核中的消息链表。进程可以向队列中添加消息(写),或从队列中读取消息(读)。

  • 原理:每个消息是一个数据块,具有特定的格式和优先级。进程通过消息队列标识符来访问同一个队列。

  • 特点

    • 克服了管道只能承载无格式字节流的缺点。

    • 独立于发送和接收进程存在(进程终止后,消息队列及其内容并不会被删除)。

    • 避免了同步阻塞问题(可以非阻塞地读写)。

3. 共享内存 (Shared Memory)
  • 概念最快的IPC方式。允许多个进程共享同一块物理内存区域。

  • 原理

    1. 由一个进程创建一块共享内存段。

    2. 其他进程通过系统调用将其映射 (attach) 到自己的地址空间中。

    3. 之后,进程就可以像访问普通内存一样读写这块区域,从而直接交换数据。

  • 特点

    • 极快:数据不需要在内核和用户空间之间来回拷贝。

    • 需要同步:因为多个进程同时读写同一块内存,必须配合使用信号量互斥锁等同步机制来确保数据一致性。

其他方式:
  • 信号 (Signal):一种异步通信机制,用于通知接收进程某个事件已经发生(如 kill -9)。携带的信息量少。

  • 套接字 (Socket):最通用的通信机制,可用于不同机器上的进程间网络通信,也支持同一台主机上的进程通信。

编程:

2.1 管道(Pipe)

#include <iostream>
#include <unistd.h>
#include <string.h>int main() {int fd[2]; // fd[0]是读端,fd[1]是写端pipe(fd); // 创建匿名管道pid_t pid = fork();if (pid == 0) { // 子进程close(fd[0]); // 关闭子进程不需要的读端const char* msg = "Hello from child via pipe!";write(fd[1], msg, strlen(msg) + 1); // 向管道写入数据close(fd[1]);} else { // 父进程close(fd[1]); // 关闭父进程不需要的写端char buffer[100];read(fd[0], buffer, sizeof(buffer)); // 从管道读取数据std::cout << "Parent received: " << buffer << std::endl;close(fd[0]);wait(nullptr);}return 0;
}

特点:单向通信,有亲缘关系的进程间使用,容量有限

2.2 命名管道(FIFO)

命名管道允许无亲缘关系的进程通信。

fifo_writer.cpp (写端)

#include <iostream>
#include <fcntl.h>   // for open
#include <unistd.h>  // for write, close
#include <cstring>   // for strlen
#include <sys/stat.h> // for mkfifoint main() {const char* fifo_name = "/tmp/my_fifo";// 创建命名管道(如果不存在)mkfifo(fifo_name, 0666); // 权限 0666std::cout << "Opening FIFO for writing...\n";int fd = open(fifo_name, O_WRONLY); // 阻塞,直到有读端打开const char* message = "Hello from Writer Process!";write(fd, message, strlen(message) + 1);std::cout << "Message sent.\n";close(fd);// 通常不删除FIFO,以便多次使用// unlink(fifo_name);return 0;
}

fifo_reader.cpp (读端)

#include <iostream>
#include <fcntl.h>
#include <unistd.h>int main() {const char* fifo_name = "/tmp/my_fifo";char buffer[100];std::cout << "Opening FIFO for reading...\n";int fd = open(fifo_name, O_RDONLY); // 阻塞,直到有写端打开read(fd, buffer, sizeof(buffer));std::cout << "Received: " << buffer << std::endl;close(fd);return 0;
}

编译运行

g++ fifo_writer.cpp -o writer
g++ fifo_reader.cpp -o reader
# 先在一个终端运行 ./writer (它会阻塞等待读者)
# 在另一个终端运行 ./reader

特点:可用于无亲缘关系的进程,有文件名,持久化

2.3 消息队列(Message Queue)

msg_sender.cpp (发送端)

#include <iostream>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <cstring>// 定义消息结构体
struct message_buffer {long msg_type;char msg_text[100];
};int main() {key_t key = ftok("progfile", 65); // 生成唯一keyint msgid = msgget(key, 0666 | IPC_CREAT); // 创建/获取消息队列message_buffer msg;msg.msg_type = 1; // 消息类型strcpy(msg.msg_text, "Hello from Message Queue!");msgsnd(msgid, &msg, sizeof(msg.msg_text), 0); // 发送消息std::cout << "Message sent: " << msg.msg_text << std::endl;return 0;
}

msg_receiver.cpp (接收端)

#include <iostream>
#include <sys/ipc.h>
#include <sys/msg.h>struct message_buffer {long msg_type;char msg_text[100];
};int main() {key_t key = ftok("progfile", 65);int msgid = msgget(key, 0666);message_buffer msg;msgrcv(msgid, &msg, sizeof(msg.msg_text), 1, 0); // 接收类型为1的消息std::cout << "Message received: " << msg.msg_text << std::endl;// 销毁消息队列msgctl(msgid, IPC_RMID, NULL);return 0;
}

编译运行

g++ msg_sender.cpp -o sender
g++ msg_receiver.cpp -o receiver
./sender
./receiver

特点:消息格式固定,支持优先级,独立于进程存在

2.4 共享内存 (Shared Memory) + 信号量 (Semaphore)

这是最经典的组合:共享内存负责高速数据传输,信号量负责同步。

shm_writer.cpp (写入端)

#include <iostream>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/sem.h> // 信号量头文件
#include <cstring>
#include <unistd.h>// 联合体,用于semctl初始化
union semun {int val;struct semid_ds *buf;unsigned short *array;
};int main() {key_t key = ftok("shmfile", 65);int shmid = shmget(key, 1024, 0666 | IPC_CREAT);char* str = (char*)shmat(shmid, (void*)0, 0);// 创建信号量key_t sem_key = ftok("semfile", 66);int semid = semget(sem_key, 1, 0666 | IPC_CREAT);union semun su;su.val = 1; // 信号量初始值为1 (互斥锁)semctl(semid, 0, SETVAL, su);struct sembuf sb = {0, -1, 0}; // P操作semop(semid, &sb, 1); // 加锁// 临界区:写入数据std::cout << "Write Data: ";std::cin.getline(str, 1024);std::cout << "Data written: " << str << std::endl;sb.sem_op = 1; // V操作semop(semid, &sb, 1); // 解锁shmdt(str);return 0;
}

shm_reader.cpp (读取端)

#include <iostream>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/sem.h>union semun {int val;struct semid_ds *buf;unsigned short *array;
};int main() {key_t key = ftok("shmfile", 65);int shmid = shmget(key, 1024, 0666);char* str = (char*)shmat(shmid, (void*)0, 0);key_t sem_key = ftok("semfile", 66);int semid = semget(sem_key, 1, 0666);struct sembuf sb = {0, -1, 0}; // P操作semop(semid, &sb, 1); // 加锁// 临界区:读取数据std::cout << "Data read: " << str << std::endl;sb.sem_op = 1; // V操作semop(semid, &sb, 1); // 解锁shmdt(str);shmctl(shmid, IPC_RMID, NULL); // 销毁共享内存semctl(semid, 0, IPC_RMID);    // 销毁信号量return 0;
}

编译运行

g++ shm_writer.cpp -o shm_writer
g++ shm_reader.cpp -o shm_reader
./shm_writer
# 输入数据后,运行
./shm_reader

特点:最快的IPC方式,需要同步机制配合

2.5 信号 (Signal)

signal_example.cpp (发送信号)

#include <iostream>
#include <sys/types.h>
#include <signal.h>
#include <unistd.h>int main() {pid_t my_pid = getpid();std::cout << "My PID is: " << my_pid << std::endl;std::cout << "Sending SIGINT signal to myself in 3 seconds...\n";sleep(3);kill(my_pid, SIGINT); // 向自己发送中断信号std::cout << "This line may not be printed.\n";return 0;
}

signal_handler.cpp (捕获和处理信号)

#include <iostream>
#include <csignal>
#include <unistd.h>// 信号处理函数
void signal_handler(int signum) {std::cout << "\nInterrupt signal (" << signum << ") received.\n";// 进行清理操作exit(signum);
}int main() {// 注册信号SIGINT和信号处理函数signal(SIGINT, signal_handler);while (true) {std::cout << "Going to sleep... (Press Ctrl+C to interrupt)\n";sleep(1);}return 0;
}

编译运行

g++ signal_handler.cpp -o handler
./handler
# 然后按 Ctrl+C 观察效果

特点:异步通知机制,用于简单事件通知

2.6 套接字 (Socket) - Unix Domain Socket (本地)

socket_server.cpp (服务端)

#include <iostream>
#include <sys/socket.h>
#include <sys/un.h>
#include <unistd.h>
#include <cstring>int main() {int server_fd, client_fd;struct sockaddr_un server_addr, client_addr;socklen_t client_len = sizeof(client_addr);char buffer[100];// 创建socketserver_fd = socket(AF_UNIX, SOCK_STREAM, 0);// 配置地址server_addr.sun_family = AF_UNIX;strcpy(server_addr.sun_path, "/tmp/demo_socket");unlink(server_addr.sun_path); // 确保文件不存在bind(server_fd, (struct sockaddr*)&server_addr, sizeof(server_addr));listen(server_fd, 5); // 开始监听std::cout << "Server waiting for connection...\n";client_fd = accept(server_fd, (struct sockaddr*)&client_addr, &client_len);read(client_fd, buffer, sizeof(buffer));std::cout << "Server received: " << buffer << std::endl;const char* reply = "Hello from Server!";write(client_fd, reply, strlen(reply) + 1);close(client_fd);close(server_fd);unlink(server_addr.sun_path);return 0;
}

socket_client.cpp (客户端)

#include <iostream>
#include <sys/socket.h>
#include <sys/un.h>
#include <unistd.h>
#include <cstring>int main() {int sockfd;struct sockaddr_un server_addr;char buffer[100];sockfd = socket(AF_UNIX, SOCK_STREAM, 0);server_addr.sun_family = AF_UNIX;strcpy(server_addr.sun_path, "/tmp/demo_socket");connect(sockfd, (struct sockaddr*)&server_addr, sizeof(server_addr));const char* message = "Hello from Client!";write(sockfd, message, strlen(message) + 1);read(sockfd, buffer, sizeof(buffer));std::cout << "Client received: " << buffer << std::endl;close(sockfd);return 0;
}

编译运行

g++ socket_server.cpp -o server
g++ socket_client.cpp -o client
# 先运行 ./server (它会等待连接)
# 再另一个终端运行 ./client

特点:最通用的IPC方式,支持网络通信

 重要说明

  1. 错误处理:以上示例省略了错误处理以便突出重点,实际使用时务必检查每个系统调用的返回值!

  2. 编译:所有示例使用 g++ 编译,不需要特殊标志(除了需要 -pthread 的线程例子)。

  3. 运行顺序:注意有些示例需要按特定顺序运行(如先server后client,先writer后reader)。

3. 同步机制

当多个执行流(进程或线程)并发地访问共享资源时,为了防止出现竞态条件 (Race Condition) 和数据不一致,需要进行同步。

1. 互斥锁 (Mutex)
  • 概念:像一把钥匙,保护一个共享资源。一次只允许一个线程访问该资源。

  • 操作

    • 加锁 (Lock):如果锁已被占用,则当前线程会被阻塞,直到锁被释放。

    • 解锁 (Unlock):释放锁,允许其他线程获取它。

  • 特点:实现简单,是最常用的同步机制。锁的持有者必须负责释放锁,否则会导致死锁。

2. 信号量 (Semaphore)
  • 概念:一个计数器,用于控制访问多个共享资源的线程数。是比互斥锁更通用的同步原语。

  • 操作

    • P操作 (Wait):尝试减少信号量的值。如果值大于0,则减少并继续;如果值为0,则线程阻塞,直到值大于0。

    • V操作 (Signal):增加信号量的值,并唤醒一个等待的线程(如果有)。

  • 类型

    • 二进制信号量:值只有0和1,功能上等价于一个互斥锁

    • 计数信号量:值可以大于1,用于控制对一组 identical 资源的访问(例如,有5个打印机的打印池,信号量初始值为5)。

3. 条件变量 (Condition Variable)
  • 概念:允许线程在某些条件不满足时主动阻塞自己释放锁,等待其他线程改变条件后通知它。它总是与一个互斥锁结合使用。

  • 操作

    • wait(cond, mutex):线程阻塞自己,并原子性地释放互斥锁 mutex。被唤醒后,它会重新获取 mutex 再返回。

    • signal(cond):唤醒一个正在 wait 的线程。

    • broadcast(cond):唤醒所有正在 wait 的线程。

  • 使用场景:非常适合用于生产者-消费者模型。当缓冲区空时,消费者线程等待;生产者生产数据后,通知消费者。反之,当缓冲区满时,生产者等待;消费者消费数据后,通知生产者。

同步方式对比总结:
机制核心思想主要用途
互斥锁 (Mutex)独占访问,一次一个。保护临界区,确保对单个共享资源的互斥访问。用于简单的互斥
信号量 (Semaphore)计数器,控制N个访问。控制对一组数量有限的相同资源的访问。用于管理资源池
条件变量 (Condition)等待条件成立,与锁配合。用于线程间协调,当某个状态条件不满足时让线程等待。用于复杂的线程状态协调

3.1 互斥锁(Mutex)

thread:

#include <iostream>
#include <thread>
#include <mutex>std::mutex mtx; // 全局互斥锁
int shared_counter = 0;void increment_counter(int id) {for (int i = 0; i < 5; ++i) {mtx.lock(); // 上锁// 临界区开始++shared_counter;std::cout << "Thread " << id << " incremented counter to: " << shared_counter << std::endl;// 临界区结束mtx.unlock(); // 解锁std::this_thread::sleep_for(std::chrono::milliseconds(10));}
}int main() {std::thread t1(increment_counter, 1);std::thread t2(increment_counter, 2);t1.join();t2.join();std::cout << "Final counter value: " << shared_counter << std::endl;return 0;
}

pthread:

#include <pthread.h>pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
int shared_data = 0;void* thread_func(void* arg) {pthread_mutex_lock(&mutex);      // 加锁shared_data++;                   // 临界区pthread_mutex_unlock(&mutex);    // 解锁return NULL;
}void mutex_example() {pthread_t t1, t2;pthread_create(&t1, NULL, thread_func, NULL);pthread_create(&t2, NULL, thread_func, NULL);pthread_join(t1, NULL);pthread_join(t2, NULL);printf("Final value: %d\n", shared_data);  // 应该是2
}

特点:最简单的同步机制,保证互斥访问

3.2 信号量(Semaphore)

pthread:

#include <semaphore.h>sem_t semaphore;
int buffer[10];
int count = 0;void* producer(void* arg) {for (int i = 0; i < 10; i++) {// 生产数据buffer[count++] = i;sem_post(&semaphore);  // V操作,信号量+1}return NULL;
}void* consumer(void* arg) {for (int i = 0; i < 10; i++) {sem_wait(&semaphore);  // P操作,信号量-1(如果为0则阻塞)// 消费数据printf("Consumed: %d\n", buffer[--count]);}return NULL;
}void semaphore_example() {sem_init(&semaphore, 0, 0);  // 初始值为0pthread_t prod, cons;pthread_create(&prod, NULL, producer, NULL);pthread_create(&cons, NULL, consumer, NULL);pthread_join(prod, NULL);pthread_join(cons, NULL);sem_destroy(&semaphore);
}

C++20 引入了 std::counting_semaphore

thread:

#include <iostream>
#include <thread>
#include <semaphore.h> // 注意:这是POSIX信号量,C++20标准信号量用法略有不同// 使用POSIX信号量(更通用)
sem_t sem;void worker(int id) {sem_wait(&sem); // P操作,获取资源std::cout << "Thread " << id << " is in critical section." << std::endl;std::this_thread::sleep_for(std::chrono::seconds(1));std::cout << "Thread " << id << " is leaving critical section." << std::endl;sem_post(&sem); // V操作,释放资源
}int main() {// 初始化信号量,初始值为2(允许2个线程同时进入)sem_init(&sem, 0, 2);std::thread t1(worker, 1);std::thread t2(worker, 2);std::thread t3(worker, 3);t1.join();t2.join();t3.join();sem_destroy(&sem); // 销毁信号量return 0;
}

特点:更灵活的同步机制,可以控制多个线程的访问

3.3 条件变量(Condition Variable)

#include <pthread.h>pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
int data_ready = 0;void* producer(void* arg) {pthread_mutex_lock(&mutex);// 生产数据data_ready = 1;pthread_cond_signal(&cond);  // 通知消费者pthread_mutex_unlock(&mutex);return NULL;
}void* consumer(void* arg) {pthread_mutex_lock(&mutex);while (!data_ready) {pthread_cond_wait(&cond, &mutex);  // 等待条件,释放锁}// 消费数据printf("Data is ready!\n");pthread_mutex_unlock(&mutex);return NULL;
}void condition_variable_example() {pthread_t prod, cons;pthread_create(&cons, NULL, consumer, NULL);sleep(1);  // 确保消费者先等待pthread_create(&prod, NULL, producer, NULL);pthread_join(prod, NULL);pthread_join(cons, NULL);
}
条件变量 (Condition Variable) - 用于线程间 (生产者-消费者模型)
#include <iostream>
#include <thread>
#include <mutex>
#include <condition_variable>
#include <queue>std::mutex mtx;
std::condition_variable cv;
std::queue<int> msgQueue; // 共享的消息队列void producer(int id) {for (int i = 0; i < 5; ++i) {std::unique_lock<std::mutex> lock(mtx);msgQueue.push(i);std::cout << "Producer " << id << " produced: " << i << std::endl;lock.unlock();cv.notify_one(); // 通知一个等待的消费者std::this_thread::sleep_for(std::chrono::milliseconds(100));}
}void consumer(int id) {while (true) {std::unique_lock<std::mutex> lock(mtx);// 等待条件成立:队列非空cv.wait(lock, []{ return !msgQueue.empty(); });int msg = msgQueue.front();msgQueue.pop();std::cout << "Consumer " << id << " consumed: " << msg << std::endl;lock.unlock();if (msg == 4) break; // 简单设定消费到4就退出}
}int main() {std::thread p1(producer, 1);std::thread c1(consumer, 1);p1.join();c1.join();return 0;
}

特点:用于线程间的条件等待和通知,必须与互斥锁配合使用

3.4 读写锁(Read-Write Lock)

#include <pthread.h>pthread_rwlock_t rwlock = PTHREAD_RWLOCK_INITIALIZER;
int shared_data = 0;void* reader(void* arg) {pthread_rwlock_rdlock(&rwlock);  // 读锁printf("Reader: %d\n", shared_data);pthread_rwlock_unlock(&rwlock);return NULL;
}void* writer(void* arg) {pthread_rwlock_wrlock(&rwlock);  // 写锁shared_data++;printf("Writer updated to: %d\n", shared_data);pthread_rwlock_unlock(&rwlock);return NULL;
}void rwlock_example() {pthread_t readers[3], writers[2];for (int i = 0; i < 2; i++) {pthread_create(&writers[i], NULL, writer, NULL);}for (int i = 0; i < 3; i++) {pthread_create(&readers[i], NULL, reader, NULL);}// 等待所有线程完成for (int i = 0; i < 2; i++) pthread_join(writers[i], NULL);for (int i = 0; i < 3; i++) pthread_join(readers[i], NULL);
}

特点:允许多个读或一个写,提高读多写少场景的性能

4. 同步机制对比

机制用途特点适用场景
互斥锁互斥访问简单,开销小简单的临界区保护
信号量资源计数灵活,可控制多个访问生产者-消费者,资源池
条件变量条件等待必须配合互斥锁使用复杂的条件同步
读写锁读写分离读并发高,写互斥读多写少的场景

5. 常见问题

Q1: 进程和线程的根本区别是什么?

:根本区别在于资源分配。进程是资源分配的基本单位,拥有独立的地址空间;线程是CPU调度的基本单位,共享进程资源。

Q2: 哪种IPC方式最快?为什么?

共享内存最快,因为它直接在内存中操作,避免了数据拷贝和系统调用开销。

Q3: 互斥锁和信号量的区别?

:互斥锁用于互斥访问(二进制信号量),信号量可以用于计数和更复杂的同步场景。

Q4: 为什么条件变量需要配合互斥锁使用?

:条件变量的等待操作需要原子地释放锁并进入等待状态,唤醒后需要重新获取锁,这需要互斥锁的配合。

Q5: 什么是死锁?如何避免?

:死锁是多个进程/线程互相等待对方释放资源。避免方法:按固定顺序获取锁、使用超时机制、避免嵌套锁、使用死锁检测算法。

6. 实际应用建议

选择正确的IPC方式

  • 高性能:共享内存 + 信号量

  • 简单通信:管道或消息队列

  • 网络通信:套接字

  • 事件通知:信号

同步最佳实践

// 使用RAII模式管理锁
void critical_section() {pthread_mutex_lock(&mutex);// 临界区操作pthread_mutex_unlock(&mutex);  // 容易忘记!
}// 更好的方式:使用锁守卫
struct MutexGuard {pthread_mutex_t* mutex;MutexGuard(pthread_mutex_t* m) : mutex(m) { pthread_mutex_lock(mutex); }~MutexGuard() { pthread_mutex_unlock(mutex); }
};void safe_critical_section() {MutexGuard guard(&mutex);  // 自动加锁// 临界区操作
} // 自动解锁,异常安全

总结

理解进程和线程的区别以及各种通信同步机制,是操作系统和并发编程的基础:

  • ✅ 进程线程区别:资源分配 vs CPU调度

  • ✅ IPC方式:根据需求选择合适通信机制

  • ✅ 同步机制:保证数据一致性和线程安全

  • ✅ 实践原则:选择合适工具,避免死锁,保证性能

2.虚拟内存:分页、分段、页面置换算法

//TODO:keep learning.

http://www.xdnf.cn/news/1471573.html

相关文章:

  • 怎么告别信息收集难题?
  • 使用海康威视 SDK 实现软触发拍照(C语言完整示例 + 中文注释)
  • 不上融资、不炒概念,它却成了全球AI“全明星”中国独苗!
  • 实战记录:H3C路由器IS-IS Level-1邻居建立与路由发布
  • 智慧公厕系统使用说明书,布线规范全解析
  • 深入理解 APPLY:写出更可读、更高性能的相关子查询
  • 原子工程用AC6编译不过问题
  • Linux ARM64 内核/用户虚拟空间地址映射
  • GMT——用于人形全身控制的通用运动跟踪:两阶段师生训练框架下,全身基于单一策略,且自适应采样、MoE架构
  • 【LLM的后训练之对齐人类篇】SFT、RLHF(RM+PPO)、DPO task09
  • Linux应用(2)——标准/目录IO
  • DPO算法
  • C++中虚函数与构造/析构函数的深度解析
  • 标注格式转换csv转xml
  • 【Hot100】回溯
  • 遇到“指责型人格”别硬碰硬!3个反拿捏技巧,让他从挑刺变闭嘴
  • 【前端教程】JavaScript DOM 操作实战案例详解
  • javafx笔记
  • 有序数组,距离目标最近的k个数 二分查找
  • 2025 年高教社杯全国大学生数学建模竞赛C 题 NIPT 的时点选择与胎儿的异常判定详解(一)
  • 数据库基础知识——聚合函数、分组查询
  • ResNet 迁移学习---加速深度学习模型训练
  • 瑞芯微RV1126目标识别算法Yolov8的部署应用
  • 关于kubernetes和docker版本的一些总结
  • 工业设备管理软件与AI_HawkEye智能运维平台_璞华大数据
  • 自定义格式化数据(BYOFD)(81)
  • Python快速入门专业版(五):从 print 到交互:Python 解释器与 IDLE 的基础使用
  • 如何在序列水平上简单分析一个新蛋白质序列(novel protein sequence)
  • AM J BOT | 黄芪稳健骨架树构建
  • 360° 拖动旋转的角度计算原理