C/Linux:线程间交替
C/Linux: Alternating between threads
所以我有这个代码:
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <unistd.h>
#include <semaphore.h>
#define nr_threads 3
sem_t semaphores[nr_threads];
typedef struct {
int id;
char *word;
}th_struct;
void *thread_function(void *arg)
{
th_struct *th_data = (th_struct *) arg;
sem_wait(&semaphores[th_data->id]);
printf("[thread#%d] %s\n", th_data->id, th_data->word);
sem_post(&semaphores[th_data->id + 1]);
return NULL;
}
int main(int argc, char **argv)
{
pthread_t tid[nr_threads];
th_struct th_data[nr_threads];
for(int i = 0; i < nr_threads; i++){
if (sem_init(&semaphores[i], 0, 1) != 0){
perror("Could not init semaphore");
return -1;
}
}
sem_post(&semaphores[0]);
for(int i = 0; i < nr_threads; i++){
th_data[i].id = i;
th_data[i].word = argv[i + 1];
pthread_create(&tid[i], NULL, thread_function, &th_data[i]);
}
for(int i = 0; i < nr_threads; i++){
pthread_join(tid[i], NULL);
}
for(int i = 0; i < nr_threads; i++)
sem_destroy(&semaphores[i]);
return 0;
}
我从命令行给出3个词,例如"one two three",每个线程打印一个词,同步的,这样顺序总是正确的。
我是线程和信号量的新手,我的大脑目前习惯于sem_wait(sem)和sem_post(sem)之后,其中sem是一样的信号。我要问的是关于此代码为何工作以及如何工作的完整解释。为什么信号量初始化为 0 权限?为什么会有sem_post(first_semaphore)?我很困惑。
首先,该代码中存在错误...
完成工作后,每个线程无条件地调用下一个线程的信号量sem_post()
。因此,第三个线程将尝试访问不存在的semaphores[3]
。
现在发生了什么(假设错误不存在)是这样的:
- 创建并初始化了 3 个信号量,以便立即锁定它们
- 创建了 3 个线程,每个线程都调用
sem_wait()
并阻塞(因为信号量被初始化为 0)
- 一个线程完成它的工作后,它在下一个线程的信号量上调用
sem_post()
,然后从 sem_wait()
returns
这是基本思路,但是要得到它运行,有人需要为第一个信号量调用sem_post()
。所以这就是为什么在 main().
中有 sem_post(&semaphores[0])
注意:这是一个很长的评论,不是一个完整的答案。
我喜欢将信号量视为无信息令牌的阻塞队列。信号量的 count 是队列中的令牌数。
从这个角度来看,程序中的主线程创建了一个令牌(从无到有,因为令牌 是 什么都没有),并将令牌交给第一个工作线程通过调用 sem_post(&semaphores[0]);
.
第一个 worker 在从其输入队列中取出令牌后能够完成其工作(即,当 sem_wait(&semaphores[th_data->id]);
returns。完成工作后,它将令牌交给下一个主题:sem_post(&semaphores[th_data->id + 1]);
所以我有这个代码:
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <unistd.h>
#include <semaphore.h>
#define nr_threads 3
sem_t semaphores[nr_threads];
typedef struct {
int id;
char *word;
}th_struct;
void *thread_function(void *arg)
{
th_struct *th_data = (th_struct *) arg;
sem_wait(&semaphores[th_data->id]);
printf("[thread#%d] %s\n", th_data->id, th_data->word);
sem_post(&semaphores[th_data->id + 1]);
return NULL;
}
int main(int argc, char **argv)
{
pthread_t tid[nr_threads];
th_struct th_data[nr_threads];
for(int i = 0; i < nr_threads; i++){
if (sem_init(&semaphores[i], 0, 1) != 0){
perror("Could not init semaphore");
return -1;
}
}
sem_post(&semaphores[0]);
for(int i = 0; i < nr_threads; i++){
th_data[i].id = i;
th_data[i].word = argv[i + 1];
pthread_create(&tid[i], NULL, thread_function, &th_data[i]);
}
for(int i = 0; i < nr_threads; i++){
pthread_join(tid[i], NULL);
}
for(int i = 0; i < nr_threads; i++)
sem_destroy(&semaphores[i]);
return 0;
}
我从命令行给出3个词,例如"one two three",每个线程打印一个词,同步的,这样顺序总是正确的。
我是线程和信号量的新手,我的大脑目前习惯于sem_wait(sem)和sem_post(sem)之后,其中sem是一样的信号。我要问的是关于此代码为何工作以及如何工作的完整解释。为什么信号量初始化为 0 权限?为什么会有sem_post(first_semaphore)?我很困惑。
首先,该代码中存在错误...
完成工作后,每个线程无条件地调用下一个线程的信号量sem_post()
。因此,第三个线程将尝试访问不存在的semaphores[3]
。
现在发生了什么(假设错误不存在)是这样的:
- 创建并初始化了 3 个信号量,以便立即锁定它们
- 创建了 3 个线程,每个线程都调用
sem_wait()
并阻塞(因为信号量被初始化为 0) - 一个线程完成它的工作后,它在下一个线程的信号量上调用
sem_post()
,然后从sem_wait()
returns
这是基本思路,但是要得到它运行,有人需要为第一个信号量调用sem_post()
。所以这就是为什么在 main().
sem_post(&semaphores[0])
注意:这是一个很长的评论,不是一个完整的答案。
我喜欢将信号量视为无信息令牌的阻塞队列。信号量的 count 是队列中的令牌数。
从这个角度来看,程序中的主线程创建了一个令牌(从无到有,因为令牌 是 什么都没有),并将令牌交给第一个工作线程通过调用 sem_post(&semaphores[0]);
.
第一个 worker 在从其输入队列中取出令牌后能够完成其工作(即,当 sem_wait(&semaphores[th_data->id]);
returns。完成工作后,它将令牌交给下一个主题:sem_post(&semaphores[th_data->id + 1]);