linux 进程与线程(实例详解)

新星杯·14天创作挑战营·第17期 10w+人浏览 488人参与

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机制容易,直接访问共享数据
独立性完全独立,崩溃不影响其他进程依赖进程,线程崩溃可能导致整个进程崩溃
上下文切换开销大开销小
资源占用
同步需求较少(天然隔离)必须同步(共享数据)
适用场景需要高隔离性、独立性的任务需要频繁通信、数据共享的任务

关键要点总结:

  1. 进程创建:使用fork(),子进程复制父进程的地址空间
  2. 线程创建:使用pthread_create(),线程共享进程地址空间
  3. 数据竞争:多个线程同时访问共享数据可能导致不一致
  4. 同步机制:互斥锁(mutex)、条件变量(condition variable)等
  5. 进程通信:管道、共享内存、消息队列等IPC机制
  6. C++线程:使用std::thread,更加面向对象

通过这些实例和运行结果,你应该能够深入理解Linux下的进程和线程编程,掌握基本的并发编程技能。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值