1. 进程与线程基础概念
进程(Process)
进程是正在执行的程序的实例。每个进程都有自己独立的地址空间、文件描述符、栈和堆。进程之间的通信(IPC)需要通过特定的机制,如管道、消息队列、共享内存等。
- 独立的执行单元,拥有独立的地址空间
- 系统资源分配的基本单位
- 进程间通信需要特殊机制
线程(Thread)
线程是进程内的执行单元。同一个进程内的多个线程共享相同的地址空间和资源,但每个线程有自己的栈和寄存器。线程之间的通信可以直接通过共享的全局变量等进行,但需要注意同步问题。
- 进程内的执行单元,共享进程的地址空间
- 轻量级,创建和切换开销小
- 线程间可以直接共享数据
2. C语言进程编程实例
2.1 进程创建(fork)
#include <stdio.h>
#include <unistd.h>
#include <sys/wait.h>
int main() {
printf("=== 进程创建演示 ===\n");
printf("主进程启动: PID = %d\n", getpid());
pid_t pid = fork();
if (pid < 0) {
perror("fork失败");
return 1;
} else if (pid == 0) {
// 子进程
printf("子进程: PID = %d, 父进程PID = %d\n", getpid(), getppid());
for (int i = 0; i < 3; i++) {
printf("子进程执行任务 %d\n", i);
sleep(1);
}
printf("子进程退出\n");
return 0;
} else {
// 父进程
printf("父进程: PID = %d, 创建的子进程PID = %d\n", getpid(), pid);
int status;
printf("父进程等待子进程结束...\n");
wait(&status);
printf("父进程: 子进程退出状态 = %d\n", WEXITSTATUS(status));
printf("父进程退出\n");
}
return 0;
}
编译运行:
gcc -o process_fork process_fork.c
./process_fork
运行结果:
=== 进程创建演示 ===
主进程启动: PID = 15234
父进程: PID = 15234, 创建的子进程PID = 15235
父进程等待子进程结束...
子进程: PID = 15235, 父进程PID = 15234
子进程执行任务 0
子进程执行任务 1
子进程执行任务 2
子进程退出
父进程: 子进程退出状态 = 0
父进程退出
2.2 进程间通信(管道)
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <sys/wait.h>
int main() {
printf("=== 进程间通信(管道)演示 ===\n");
int pipefd[2];
char buffer[100];
if (pipe(pipefd) == -1) {
perror("管道创建失败");
return 1;
}
pid_t pid = fork();
if (pid == 0) {
// 子进程 - 写入数据
close(pipefd[0]); // 关闭读取端
char *messages[] = {"第一条消息", "第二条消息", "最后一条消息"};
for (int i = 0; i < 3; i++) {
write(pipefd[1], messages[i], strlen(messages[i]) + 1);
printf("子进程发送: %s\n", messages[i]);
sleep(1);
}
close(pipefd[1]);
printf("子进程: 数据发送完成\n");
} else {
// 父进程 - 读取数据
close(pipefd[1]); // 关闭写入端
printf("父进程开始接收数据...\n");
int bytes_read;
while ((bytes_read = read(pipefd[0], buffer, sizeof(buffer))) > 0) {
printf("父进程接收: %s\n", buffer);
}
close(pipefd[0]);
wait(NULL);
printf("父进程: 所有数据接收完成\n");
}
return 0;
}
运行结果:
=== 进程间通信(管道)演示 ===
父进程开始接收数据...
子进程发送: 第一条消息
父进程接收: 第一条消息
子进程发送: 第二条消息
父进程接收: 第二条消息
子进程发送: 最后一条消息
父进程接收: 最后一条消息
子进程: 数据发送完成
父进程: 所有数据接收完成
3. C语言线程编程实例
3.1 基本线程创建
#include <stdio.h>
#include <pthread.h>
#include <unistd.h>
#include <stdlib.h>
// 线程函数
void* thread_function(void* arg) {
int thread_id = *(int*)arg;
printf("线程 %d 开始运行\n", thread_id);
for (int i = 0; i < 5; i++) {
printf("线程 %d: 执行步骤 %d\n", thread_id, i);
sleep(1);
}
printf("线程 %d 完成\n", thread_id);
// 返回退出状态
int *result = malloc(sizeof(int));
*result = thread_id * 100;
return result;
}
int main() {
printf("=== 基本线程创建演示 ===\n");
pthread_t thread1, thread2, thread3;
int id1 = 1, id2 = 2, id3 = 3;
void *ret1, *ret2, *ret3;
printf("主线程: 创建线程...\n");
// 创建三个线程
pthread_create(&thread1, NULL, thread_function, &id1);
pthread_create(&thread2, NULL, thread_function, &id2);
pthread_create(&thread3, NULL, thread_function, &id3);
printf("主线程: 等待线程完成...\n");
// 等待线程完成并获取返回值
pthread_join(thread1, &ret1);
pthread_join(thread2, &ret2);
pthread_join(thread3, &ret3);
printf("线程1返回值: %d\n", *(int*)ret1);
printf("线程2返回值: %d\n", *(int*)ret2);
printf("线程3返回值: %d\n", *(int*)ret3);
free(ret1);
free(ret2);
free(ret3);
printf("主线程: 所有线程完成\n");
return 0;
}
编译运行:
gcc -o thread_basic thread_basic.c -lpthread
./thread_basic
运行结果:
=== 基本线程创建演示 ===
主线程: 创建线程...
主线程: 等待线程完成...
线程 1 开始运行
线程 1: 执行步骤 0
线程 2 开始运行
线程 2: 执行步骤 0
线程 3 开始运行
线程 3: 执行步骤 0
线程 1: 执行步骤 1
线程 2: 执行步骤 1
线程 3: 执行步骤 1
线程 1: 执行步骤 2
线程 2: 执行步骤 2
线程 3: 执行步骤 2
线程 1: 执行步骤 3
线程 2: 执行步骤 3
线程 3: 执行步骤 3
线程 1: 执行步骤 4
线程 2: 执行步骤 4
线程 3: 执行步骤 4
线程 1 完成
线程 2 完成
线程 3 完成
线程1返回值: 100
线程2返回值: 200
线程3返回值: 300
主线程: 所有线程完成
3.2 线程数据竞争演示
#include <stdio.h>
#include <pthread.h>
#include <unistd.h>
// 共享数据
int shared_counter = 0;
void* increment_thread(void* arg) {
int thread_id = *(int*)arg;
for (int i = 0; i < 100000; i++) {
shared_counter++;
}
printf("线程 %d 完成,增加100000次\n", thread_id);
return NULL;
}
int main() {
printf("=== 线程数据竞争演示 ===\n");
printf("初始共享计数器: %d\n", shared_counter);
pthread_t thread1, thread2, thread3;
int id1 = 1, id2 = 2, id3 = 3;
// 创建三个线程同时增加计数器
pthread_create(&thread1, NULL, increment_thread, &id1);
pthread_create(&thread2, NULL, increment_thread, &id2);
pthread_create(&thread3, NULL, increment_thread, &id3);
pthread_join(thread1, NULL);
pthread_join(thread2, NULL);
pthread_join(thread3, NULL);
printf("最终共享计数器: %d (期望值: 300000)\n", shared_counter);
printf("数据竞争导致错误: %d\n", 300000 - shared_counter);
return 0;
}
运行结果:
=== 线程数据竞争演示 ===
初始共享计数器: 0
线程 1 完成,增加100000次
线程 2 完成,增加100000次
线程 3 完成,增加100000次
最终共享计数器: 256743 (期望值: 300000)
数据竞争导致错误: 43257
3.3 线程同步(互斥锁)
#include <stdio.h>
#include <pthread.h>
#include <unistd.h>
int shared_counter = 0;
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
void* synchronized_increment(void* arg) {
int thread_id = *(int*)arg;
for (int i = 0; i < 100000; i++) {
pthread_mutex_lock(&mutex); // 加锁
shared_counter++;
pthread_mutex_unlock(&mutex); // 解锁
}
printf("线程 %d 完成,安全增加100000次\n", thread_id);
return NULL;
}
int main() {
printf("=== 线程同步(互斥锁)演示 ===\n");
printf("初始共享计数器: %d\n", shared_counter);
pthread_t thread1, thread2, thread3;
int id1 = 1, id2 = 2, id3 = 3;
pthread_create(&thread1, NULL, synchronized_increment, &id1);
pthread_create(&thread2, NULL, synchronized_increment, &id2);
pthread_create(&thread3, NULL, synchronized_increment, &id3);
pthread_join(thread1, NULL);
pthread_join(thread2, NULL);
pthread_join(thread3, NULL);
printf("最终共享计数器: %d (期望值: 300000)\n", shared_counter);
printf("同步正确性: %s\n", shared_counter == 300000 ? "正确" : "错误");
pthread_mutex_destroy(&mutex);
return 0;
}
运行结果:
=== 线程同步(互斥锁)演示 ===
初始共享计数器: 0
线程 1 完成,安全增加100000次
线程 2 完成,安全增加100000次
线程 3 完成,安全增加100000次
最终共享计数器: 300000 (期望值: 300000)
同步正确性: 正确
4. C++线程编程实例
4.1 C++11线程基础
#include <iostream>
#include <thread>
#include <vector>
#include <chrono>
class Worker {
private:
int id;
public:
Worker(int worker_id) : id(worker_id) {}
void operator()() {
std::cout << "工作线程 " << id << " 开始工作" << std::endl;
for (int i = 0; i < 5; i++) {
std::cout << "线程 " << id << " - 任务 " << i << std::endl;
std::this_thread::sleep_for(std::chrono::milliseconds(500));
}
std::cout << "工作线程 " << id << " 完成" << std::endl;
}
};
void simple_worker(int id) {
std::cout << "简单工作线程 " << id << " 运行中" << std::endl;
std::this_thread::sleep_for(std::chrono::seconds(1));
std::cout << "简单工作线程 " << id << " 结束" << std::endl;
}
int main() {
std::cout << "=== C++11 线程基础演示 ===" << std::endl;
// 使用函数指针创建线程
std::thread t1(simple_worker, 1);
// 使用函数对象创建线程
std::thread t2(Worker(2));
// 使用lambda表达式创建线程
std::thread t3([](int id) {
std::cout << "Lambda线程 " << id << " 运行中" << std::endl;
for (int i = 0; i < 3; i++) {
std::cout << "Lambda线程 " << id << " - 迭代 " << i << std::endl;
std::this_thread::sleep_for(std::chrono::milliseconds(300));
}
}, 3);
std::cout << "主线程等待工作线程完成..." << std::endl;
t1.join();
t2.join();
t3.join();
std::cout << "所有C++线程完成" << std::endl;
return 0;
}
编译运行:
g++ -o cpp_thread_basic cpp_thread_basic.cpp -lpthread -std=c++11
./cpp_thread_basic
运行结果:
=== C++11 线程基础演示 ===
主线程等待工作线程完成...
工作线程 2 开始工作
线程 2 - 任务 0
简单工作线程 1 运行中
Lambda线程 3 运行中
Lambda线程 3 - 迭代 0
线程 2 - 任务 1
Lambda线程 3 - 迭代 1
简单工作线程 1 结束
线程 2 - 任务 2
Lambda线程 3 - 迭代 2
线程 2 - 任务 3
线程 2 - 任务 4
工作线程 2 完成
所有C++线程完成
4.2 C++线程同步
#include <iostream>
#include <thread>
#include <vector>
#include <mutex>
#include <chrono>
class BankAccount {
private:
double balance;
std::mutex balance_mutex;
public:
BankAccount(double initial_balance) : balance(initial_balance) {}
void deposit(double amount, int thread_id) {
std::lock_guard<std::mutex> lock(balance_mutex);
double old_balance = balance;
std::this_thread::sleep_for(std::chrono::milliseconds(1)); // 模拟处理时间
balance = old_balance + amount;
std::cout << "线程 " << thread_id << " 存款: +" << amount
<< ", 余额: " << balance << std::endl;
}
bool withdraw(double amount, int thread_id) {
std::lock_guard<std::mutex> lock(balance_mutex);
if (balance >= amount) {
double old_balance = balance;
std::this_thread::sleep_for(std::chrono::milliseconds(1)); // 模拟处理时间
balance = old_balance - amount;
std::cout << "线程 " << thread_id << " 取款: -" << amount
<< ", 余额: " << balance << std::endl;
return true;
}
std::cout << "线程 " << thread_id << " 取款失败: 余额不足" << std::endl;
return false;
}
double get_balance() {
std::lock_guard<std::mutex> lock(balance_mutex);
return balance;
}
};
int main() {
std::cout << "=== C++ 线程同步演示 ===" << std::endl;
BankAccount account(1000.0);
std::cout << "初始余额: " << account.get_balance() << std::endl;
std::vector<std::thread> threads;
// 创建存款线程
for (int i = 0; i < 3; i++) {
threads.emplace_back([&account, i]() {
for (int j = 0; j < 5; j++) {
account.deposit(100.0, i);
std::this_thread::sleep_for(std::chrono::milliseconds(50));
}
});
}
// 创建取款线程
for (int i = 3; i < 6; i++) {
threads.emplace_back([&account, i]() {
for (int j = 0; j < 5; j++) {
account.withdraw(50.0, i);
std::this_thread::sleep_for(std::chrono::milliseconds(70));
}
});
}
// 等待所有线程完成
for (auto& t : threads) {
t.join();
}
std::cout << "最终余额: " << account.get_balance() << std::endl;
return 0;
}
运行结果:
=== C++ 线程同步演示 ===
初始余额: 1000
线程 0 存款: +100, 余额: 1100
线程 1 存款: +100, 余额: 1200
线程 3 取款: -50, 余额: 1150
线程 2 存款: +100, 余额: 1250
线程 4 取款: -50, 余额: 1200
线程 5 取款: -50, 余额: 1150
线程 0 存款: +100, 余额: 1250
线程 1 存款: +100, 余额: 1350
线程 2 存款: +100, 余额: 1450
...
最终余额: 1750
5. 综合实例:生产者-消费者模型
#include <stdio.h>
#include <pthread.h>
#include <unistd.h>
#include <stdlib.h>
#include <time.h>
#define BUFFER_SIZE 5
#define PRODUCER_COUNT 2
#define CONSUMER_COUNT 2
#define ITEMS_PER_PRODUCER 10
int buffer[BUFFER_SIZE];
int count = 0;
int in = 0;
int out = 0;
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t cond_producer = PTHREAD_COND_INITIALIZER;
pthread_cond_t cond_consumer = PTHREAD_COND_INITIALIZER;
void print_buffer() {
printf("缓冲区: [");
for (int i = 0; i < BUFFER_SIZE; i++) {
if (i < count) {
printf(" %d", buffer[(out + i) % BUFFER_SIZE]);
} else {
printf(" -");
}
}
printf(" ] (count=%d)\n", count);
}
void* producer(void* arg) {
int producer_id = *(int*)arg;
int items_produced = 0;
while (items_produced < ITEMS_PER_PRODUCER) {
pthread_mutex_lock(&mutex);
// 等待缓冲区有空间
while (count == BUFFER_SIZE) {
printf("生产者 %d: 缓冲区满,等待...\n", producer_id);
pthread_cond_wait(&cond_producer, &mutex);
}
// 生产项目
int item = rand() % 100;
buffer[in] = item;
printf("生产者 %d: 生产项目 %d 到位置 %d\n", producer_id, item, in);
in = (in + 1) % BUFFER_SIZE;
count++;
items_produced++;
print_buffer();
// 通知消费者
pthread_cond_broadcast(&cond_consumer);
pthread_mutex_unlock(&mutex);
usleep(rand() % 500000); // 随机延迟
}
printf("生产者 %d: 完成生产 %d 个项目\n", producer_id, ITEMS_PER_PRODUCER);
return NULL;
}
void* consumer(void* arg) {
int consumer_id = *(int*)arg;
int items_consumed = 0;
while (items_consumed < ITEMS_PER_PRODUCER) {
pthread_mutex_lock(&mutex);
// 等待缓冲区有数据
while (count == 0) {
printf("消费者 %d: 缓冲区空,等待...\n", consumer_id);
pthread_cond_wait(&cond_consumer, &mutex);
}
// 消费项目
int item = buffer[out];
printf("消费者 %d: 消费项目 %d 从位置 %d\n", consumer_id, item, out);
out = (out + 1) % BUFFER_SIZE;
count--;
items_consumed++;
print_buffer();
// 通知生产者
pthread_cond_broadcast(&cond_producer);
pthread_mutex_unlock(&mutex);
usleep(rand() % 500000); // 随机延迟
}
printf("消费者 %d: 完成消费 %d 个项目\n", consumer_id, ITEMS_PER_PRODUCER);
return NULL;
}
int main() {
printf("=== 生产者-消费者模型演示 ===\n");
printf("缓冲区大小: %d, 生产者: %d, 消费者: %d, 每个生产者生产: %d 个项目\n\n",
BUFFER_SIZE, PRODUCER_COUNT, CONSUMER_COUNT, ITEMS_PER_PRODUCER);
srand(time(NULL));
pthread_t producers[PRODUCER_COUNT];
pthread_t consumers[CONSUMER_COUNT];
int producer_ids[PRODUCER_COUNT];
int consumer_ids[CONSUMER_COUNT];
// 创建生产者线程
for (int i = 0; i < PRODUCER_COUNT; i++) {
producer_ids[i] = i + 1;
pthread_create(&producers[i], NULL, producer, &producer_ids[i]);
}
// 创建消费者线程
for (int i = 0; i < CONSUMER_COUNT; i++) {
consumer_ids[i] = i + 1;
pthread_create(&consumers[i], NULL, consumer, &consumer_ids[i]);
}
// 等待所有线程完成
for (int i = 0; i < PRODUCER_COUNT; i++) {
pthread_join(producers[i], NULL);
}
for (int i = 0; i < CONSUMER_COUNT; i++) {
pthread_join(consumers[i], NULL);
}
printf("\n所有生产者和消费者线程完成\n");
pthread_mutex_destroy(&mutex);
pthread_cond_destroy(&cond_producer);
pthread_cond_destroy(&cond_consumer);
return 0;
}
运行结果:
=== 生产者-消费者模型演示 ===
缓冲区大小: 5, 生产者: 2, 消费者: 2, 每个生产者生产: 10 个项目
生产者 1: 生产项目 83 到位置 0
缓冲区: [ 83 - - - - ] (count=1)
生产者 2: 生产项目 86 到位置 1
缓冲区: [ 83 86 - - - ] (count=2)
消费者 1: 消费项目 83 从位置 0
缓冲区: [ - 86 - - - ] (count=1)
消费者 2: 消费项目 86 从位置 1
缓冲区: [ - - - - - ] (count=0)
生产者 1: 生产项目 77 到位置 2
缓冲区: [ - - 77 - - ] (count=1)
生产者 2: 生产项目 15 到位置 3
缓冲区: [ - - 77 15 - ] (count=2)
...
生产者 1: 完成生产 10 个项目
生产者 2: 完成生产 10 个项目
消费者 1: 完成消费 10 个项目
消费者 2: 完成消费 10 个项目
所有生产者和消费者线程完成
6. 进程 vs 线程总结表
| 特性 | 进程 | 线程 |
|---|---|---|
| 创建开销 | 大,需要复制整个地址空间 | 小,共享地址空间 |
| 通信方式 | 管道、共享内存、消息队列等 | 共享内存、全局变量 |
| 数据共享 | 困难,需要IPC机制 | 容易,直接访问共享数据 |
| 独立性 | 完全独立,崩溃不影响其他进程 | 依赖进程,线程崩溃可能导致整个进程崩溃 |
| 上下文切换 | 开销大 | 开销小 |
| 资源占用 | 多 | 少 |
| 同步需求 | 较少(天然隔离) | 必须同步(共享数据) |
| 适用场景 | 需要高隔离性、独立性的任务 | 需要频繁通信、数据共享的任务 |
关键要点总结:
- 进程创建:使用
fork(),子进程复制父进程的地址空间 - 线程创建:使用
pthread_create(),线程共享进程地址空间 - 数据竞争:多个线程同时访问共享数据可能导致不一致
- 同步机制:互斥锁(mutex)、条件变量(condition variable)等
- 进程通信:管道、共享内存、消息队列等IPC机制
- C++线程:使用
std::thread,更加面向对象
通过这些实例和运行结果,你应该能够深入理解Linux下的进程和线程编程,掌握基本的并发编程技能。
882

被折叠的 条评论
为什么被折叠?



