C语言多线程编程实战

2025-05发布6次浏览

C语言本身并不直接支持多线程编程,但通过结合操作系统提供的线程库(如POSIX Threads,即pthread),可以实现多线程编程。在本篇文章中,我们将深入探讨如何使用C语言进行多线程编程,并通过实战案例加深理解。

1. 多线程编程基础

多线程编程是指在一个程序中创建多个线程来同时执行不同的任务。每个线程可以看作是一个独立的执行路径,它们共享同一个进程的内存空间,但拥有自己的栈和寄存器状态。

线程的优点:

  • 提高程序响应性:某些任务可以并行运行,避免阻塞主线程。
  • 充分利用多核CPU:现代计算机通常配备多核处理器,多线程可以让程序更好地利用这些资源。
  • 简化复杂任务的管理:将复杂的任务分解为多个小任务,分别由不同的线程处理。

线程的缺点:

  • 线程间竞争:多个线程可能访问同一块数据,导致竞态条件。
  • 调试困难:由于线程的行为是并发的,因此很难预测和重现错误。

2. 使用pthread库进行多线程编程

POSIX Threads(pthread)是UNIX/Linux平台下标准的线程API。下面我们将介绍如何使用pthread库创建和管理线程。

创建线程

要创建一个新线程,需要使用pthread_create函数。其原型如下:

int pthread_create(pthread_t *thread, const pthread_attr_t *attr,
                   void *(*start_routine) (void *), void *arg);
  • thread: 指向线程标识符的指针。
  • attr: 线程属性(通常设置为NULL以使用默认属性)。
  • start_routine: 新线程将执行的函数。
  • arg: 传递给start_routine的参数。

示例代码

以下是一个简单的例子,展示了如何创建两个线程并在其中打印消息:

#include <stdio.h>
#include <pthread.h>

void* print_message_function(void* ptr) {
    char* message = (char*)ptr;
    printf("%s\n", message);
    return NULL;
}

int main() {
    pthread_t thread1, thread2;
    const char* message1 = "Thread 1";
    const char* message2 = "Thread 2";

    int create_thread1 = pthread_create(&thread1, NULL, print_message_function, (void*)message1);
    int create_thread2 = pthread_create(&thread2, NULL, print_message_function, (void*)message2);

    if (create_thread1 || create_thread2) {
        fprintf(stderr, "Error creating threads.\n");
        return 1;
    }

    // 等待线程完成
    pthread_join(thread1, NULL);
    pthread_join(thread2, NULL);

    return 0;
}

线程同步

当多个线程访问共享资源时,可能会出现竞态条件。为了避免这种情况,可以使用互斥锁(mutex)来保护共享资源。

pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;

void* thread_function(void* arg) {
    pthread_mutex_lock(&lock);
    // 访问共享资源
    pthread_mutex_unlock(&lock);
    return NULL;
}

3. 实战案例:生产者消费者问题

生产者消费者问题是经典的多线程问题之一。在这个问题中,有一个缓冲区,生产者线程向缓冲区添加数据,而消费者线程从缓冲区移除数据。

解决方案设计

我们可以使用条件变量来通知消费者有新的数据可用,或者通知生产者缓冲区已空。

sequenceDiagram
    participant 生产者 as Producer
    participant 缓冲区 as Buffer
    participant 消费者 as Consumer

    loop 数据未满
        生产者->>Buffer: 添加数据
        alt 缓冲区已满
            Buffer-->>Producer: 等待
        end
    end

    loop 数据未空
        Buffer-->>Consumer: 提取数据
        alt 缓冲区为空
            Consumer-->>Buffer: 等待
        end
    end

示例代码

以下是用pthread实现的生产者消费者问题的代码片段:

#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>

#define BUFFER_SIZE 5

int buffer[BUFFER_SIZE];
int count = 0, in = 0, out = 0;

pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t cond_nonfull = PTHREAD_COND_INITIALIZER;
pthread_cond_t cond_nonempty = PTHREAD_COND_INITIALIZER;

void* producer(void* arg) {
    while (1) {
        pthread_mutex_lock(&mutex);
        while (count == BUFFER_SIZE) {
            pthread_cond_wait(&cond_nonfull, &mutex);
        }
        int item = rand() % 100;
        buffer[in] = item;
        in = (in + 1) % BUFFER_SIZE;
        count++;
        printf("Produced: %d\n", item);
        pthread_cond_signal(&cond_nonempty);
        pthread_mutex_unlock(&mutex);
    }
}

void* consumer(void* arg) {
    while (1) {
        pthread_mutex_lock(&mutex);
        while (count == 0) {
            pthread_cond_wait(&cond_nonempty, &mutex);
        }
        int item = buffer[out];
        out = (out + 1) % BUFFER_SIZE;
        count--;
        printf("Consumed: %d\n", item);
        pthread_cond_signal(&cond_nonfull);
        pthread_mutex_unlock(&mutex);
    }
}

int main() {
    pthread_t prod_thread, cons_thread;

    pthread_create(&prod_thread, NULL, producer, NULL);
    pthread_create(&cons_thread, NULL, consumer, NULL);

    pthread_join(prod_thread, NULL);
    pthread_join(cons_thread, NULL);

    return 0;
}