12.1 多线程基础
1. 什么是线程
线程是进程中的一个执行单元,每个线程都共享进程的内存空间,但有自己独立的栈空间。使用多线程可以使程序同时执行多个任务。
2. POSIX线程(pthread
)库
POSIX线程库是C语言中用于多线程编程的标准库。它提供了创建、管理、同步线程的API。
编译时链接pthread
库:
gcc your_program.c -o your_program -lpthread
12.2 创建和管理线程
1. 创建线程
使用 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
:传递给线程函数的参数。
示例:
#include <stdio.h>
#include <pthread.h>
void *printMessage(void *arg) {
printf("Hello from thread!\n");
return NULL;
}
int main() {
pthread_t thread; // 线程标识符
// 创建线程
if (pthread_create(&thread, NULL, printMessage, NULL) != 0) {
printf("Error creating thread\n");
return 1;
}
// 等待线程结束
pthread_join(thread, NULL);
printf("Thread has finished execution.\n");
return 0;
}
2. 等待线程完成
使用 pthread_join
等待线程完成执行。
语法:
int pthread_join(pthread_t thread, void **retval);
thread
:线程标识符。retval
:线程退出状态的指针(可以为NULL
)。
12.3 线程同步
在多线程环境中,多个线程可能同时访问共享资源,导致数据不一致的问题。使用同步机制(如互斥锁、条件变量等)来防止这种情况。
1. 互斥锁
互斥锁(mutex
)用于确保同一时刻只有一个线程访问共享资源。
相关函数:
pthread_mutex_init
:初始化互斥锁。pthread_mutex_lock
:加锁。pthread_mutex_unlock
:解锁。pthread_mutex_destroy
:销毁互斥锁。
示例:
#include <stdio.h>
#include <pthread.h>
pthread_mutex_t lock;
int counter = 0;
void *incrementCounter(void *arg) {
pthread_mutex_lock(&lock); // 加锁
counter++;
printf("Counter: %d\n", counter);
pthread_mutex_unlock(&lock); // 解锁
return NULL;
}
int main() {
pthread_t threads[5];
// 初始化互斥锁
pthread_mutex_init(&lock, NULL);
// 创建多个线程
for (int i = 0; i < 5; i++) {
pthread_create(&threads[i], NULL, incrementCounter, NULL);
}
// 等待所有线程完成
for (int i = 0; i < 5; i++) {
pthread_join(threads[i], NULL);
}
// 销毁互斥锁
pthread_mutex_destroy(&lock);
return 0;
}
2. 条件变量
条件变量(condition variable
)用于使线程在某个条件成立前进入等待状态,并在条件成立时唤醒线程。
相关函数:
pthread_cond_init
:初始化条件变量。pthread_cond_wait
:等待条件变量。pthread_cond_signal
:唤醒一个等待条件变量的线程。pthread_cond_broadcast
:唤醒所有等待条件变量的线程。pthread_cond_destroy
:销毁条件变量。
示例:
#include <stdio.h>
#include <pthread.h>
pthread_mutex_t lock;
pthread_cond_t cond;
int ready = 0;
void *waitForSignal(void *arg) {
pthread_mutex_lock(&lock);
while (!ready) {
pthread_cond_wait(&cond, &lock); // 等待信号
}
printf("Thread received signal.\n");
pthread_mutex_unlock(&lock);
return NULL;
}
void *sendSignal(void *arg) {
pthread_mutex_lock(&lock);
ready = 1;
pthread_cond_signal(&cond); // 发送信号
pthread_mutex_unlock(&lock);
return NULL;
}
int main() {
pthread_t thread1, thread2;
// 初始化互斥锁和条件变量
pthread_mutex_init(&lock, NULL);
pthread_cond_init(&cond, NULL);
// 创建线程
pthread_create(&thread1, NULL, waitForSignal, NULL);
pthread_create(&thread2, NULL, sendSignal, NULL);
// 等待线程完成
pthread_join(thread1, NULL);
pthread_join(thread2, NULL);
// 销毁互斥锁和条件变量
pthread_mutex_destroy(&lock);
pthread_cond_destroy(&cond);
return 0;
}
12.4 线程属性
线程属性(pthread_attr_t
)用于设置线程的行为,如分离状态、栈大小、调度策略等。
相关函数:
pthread_attr_init
:初始化线程属性对象。pthread_attr_setdetachstate
:设置线程分离状态。pthread_attr_destroy
:销毁线程属性对象。
示例:设置线程为分离状态
#include <stdio.h>
#include <pthread.h>
void *threadFunction(void *arg) {
printf("Hello from detached thread!\n");
return NULL;
}
int main() {
pthread_t thread;
pthread_attr_t attr;
// 初始化线程属性对象
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); // 设置线程为分离状态
// 创建分离线程
pthread_create(&thread, &attr, threadFunction, NULL);
// 销毁线程属性对象
pthread_attr_destroy(&attr);
// 主线程不需要等待分离线程
printf("Main thread finished.\n");
return 0;
}
12.5 线程安全
在多线程编程中,需要确保所有共享数据的访问都是线程安全的。使用互斥锁、条件变量和原子操作(如__sync
函数)可以保证线程安全。
练习
- 编写一个程序,创建多个线程,每个线程递增一个共享计数器100次,并使用互斥锁确保线程安全。
- 编写一个生产者-消费者程序,使用条件变量和互斥锁来同步生产者和消费者线程的操作。
- 使用POSIX线程库编写一个简单的线程池,实现线程的复用和任务的分发。
- 编写一个程序,模拟一个简单的银行账户系统,允许多个线程同时执行存款和取款操作,确保数据一致性。
完成这些练习后,你将掌握C语言的多线程编程。