利用信号量实现线程顺序执行
线程顺序循环执行的场景在多线程编程中并不罕见,尤其是在需要协调多个线程按特定顺序重复执行任务的情况下。以下是几个常见的例子:
- 生产者-消费者模型:在这种模型中,生产者线程生成数据并将其放入缓冲区,而消费者线程从缓冲区取出数据进行处理。这种情况下,生产者和消费者线程通常按顺序交替运行。
- 流水线处理:在某些应用中,数据处理分为多个步骤,每个步骤由不同的线程负责。例如,在图像处理流水线中,可能有一个线程读取图像数据,一个线程处理图像,一个线程保存处理后的图像。每个线程按顺序操作,形成一个循环处理流水线。
- 周期性任务调度:某些系统需要周期性地执行一组任务,例如传感器数据采集系统,每个传感器的数据采集线程需要按顺序运行,并且在一定时间后重新开始。
为了更好地理解,我们可以通过一个具体的例子来说明如何使用信号量和多线程实现顺序循环执行。
利用POSIX无名信号量实现三个线程 T1、T2 和 T3,按顺序循环执行各自的任务。
#include <stdio.h>
#include <pthread.h>
#include <semaphore.h>
#include <unistd.h>
#define NUM_ITERATIONS 3
sem_t sem1, sem2, sem3;
void* thread1(void* arg) {
for (int i = 0; i < NUM_ITERATIONS; ++i) {
sem_wait(&sem1); // 等待信号量
printf("Thread 1 is running\n");
sleep(1); // 模拟工作
printf("Thread 1 has finished\n");
sem_post(&sem2); // 通知thread2可以开始
}
return NULL;
}
void* thread2(void* arg) {
for (int i = 0; i < NUM_ITERATIONS; ++i) {
sem_wait(&sem2); // 等待信号量
printf("Thread 2 is running\n");
sleep(1); // 模拟工作
printf("Thread 2 has finished\n");
sem_post(&sem3); // 通知thread3可以开始
}
return NULL;
}
void* thread3(void* arg) {
for (int i = 0; i < NUM_ITERATIONS; ++i) {
sem_wait(&sem3); // 等待信号量
printf("Thread 3 is running\n");
sleep(1); // 模拟工作
printf("Thread 3 has finished\n");
sem_post(&sem1); // 通知thread1可以开始
}
return NULL;
}
int main() {
pthread_t t1, t2, t3;
// 初始化信号量
sem_init(&sem1, 0, 1); // 初始信号量为1,使线程1首先运行
sem_init(&sem2, 0, 0);
sem_init(&sem3, 0, 0);
/*
int sem_init(sem_t *sem, int pshared, unsigned int value);
pshared信号量的作用范围,0为线程间,非0为进程间
value 信号量值,首先执行的线程信号量设置为1,其他的为0
*/
// 创建线程
pthread_create(&t1, NULL, thread1, NULL);
pthread_create(&t2, NULL, thread2, NULL);
pthread_create(&t3, NULL, thread3, NULL);
// 等待所有线程完成
pthread_join(t1, NULL);
pthread_join(t2, NULL);
pthread_join(t3, NULL);
// 销毁信号量
sem_destroy(&sem1);
sem_destroy(&sem2);
sem_destroy(&sem3);
printf("All threads have finished execution.\n");
return 0;
}
输出结果:
Thread 1 is running
Thread 1 has finished
Thread 2 is running
Thread 2 has finished
Thread 3 is running
Thread 3 has finished
Thread 1 is running
Thread 1 has finished
Thread 2 is running
Thread 2 has finished
Thread 3 is running
Thread 3 has finished
Thread 1 is running
Thread 1 has finished
Thread 2 is running
...