C语言本身并不直接支持多线程编程,但通过结合操作系统提供的线程库(如POSIX Threads,即pthread),可以实现多线程编程。在本篇文章中,我们将深入探讨如何使用C语言进行多线程编程,并通过实战案例加深理解。
多线程编程是指在一个程序中创建多个线程来同时执行不同的任务。每个线程可以看作是一个独立的执行路径,它们共享同一个进程的内存空间,但拥有自己的栈和寄存器状态。
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;
}
生产者消费者问题是经典的多线程问题之一。在这个问题中,有一个缓冲区,生产者线程向缓冲区添加数据,而消费者线程从缓冲区移除数据。
我们可以使用条件变量来通知消费者有新的数据可用,或者通知生产者缓冲区已空。
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;
}