在多个线程之间共享变量
Share variable between multiple threads
我正在创建火车站模拟。从文件中读取列车信息。文件的每一行代表一列火车,每列火车都有自己的线程。火车站的主轨道一次只能容纳1列火车。这是我的代码:
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <string.h>
#include <readline/readline.h>
#include <unistd.h>
pthread_mutex_t main_track_mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t main_track_condition_var = PTHREAD_COND_INITIALIZER;
int main_track_status = 0;
void *train_function(void *args) {
/* Parse train information */
int line_number = atoi(strtok(args, ":,"));
char *priority_direction = strtok(NULL,":,");
int loading_time = atoi(strtok(NULL, ":,"));
int crossing_time = atoi(strtok(NULL, ":,"));
/* Load train */
sleep(loading_time/10);
printf("Train %d is ready to go %s\n",line_number,priority_direction);
/* If the main track is currently in use, wait for it to become available */
while(main_track_status)
pthread_cond_wait(&main_track_condition_var, &main_track_mutex);
/* Use the main track */
pthread_mutex_lock(&main_track_mutex);
main_track_status = 1;
printf("Train %d is ON the main track going %s\n",line_number,priority_direction);
sleep(crossing_time/10);
main_track_status = 0;
/* Notify other trains main track is empty */
pthread_mutex_unlock(&main_track_mutex);
pthread_cond_signal(&main_track_condition_var);
printf("Train %d is OFF the main track after going %s\n",line_number,priority_direction);
pthread_exit(0);
}
int main() {
FILE *ptr_file;
char buff[10];
int train_count = 0;
char *train;
char line[15];
pthread_t trains[3];
ptr_file = fopen("./trains.txt", "r");
if (!ptr_file)
{
perror("fopen for trains.txt failed");
exit(EXIT_FAILURE);
}
/* Create train for each line of file */
while (fgets(buff,10, ptr_file)!=NULL) {
train = (char*)malloc(10 * sizeof(char));
/* Include line number from file in train information */
sprintf(line, "%d:", train_count);
strcat(line, buff);
strcpy(train, line);
if(pthread_create(&trains[train_count], NULL, &train_function, (void *) train))
{
perror("pthread create failed");
exit(EXIT_FAILURE);
}
train_count++;
}
fclose(ptr_file);
/* Wait for all trains to leave the station */
for (int x = 0; x < train_count; x++) {
pthread_join(trains[x], NULL);
}
free(train);
exit(EXIT_SUCCESS);
}
火车输入文件:
e:10,6
W:5,7
E:3,10
程序的输出是:
Train 1 is ready to go W
Train 1 is ON the main track going W
Train 1 is OFF the main track after going W
Train 2 is ready to go E
Train 2 is ON the main track going E
Train 0 is ready to go e
Train 2 is OFF the main track after going E
我认为我的错误在于train_function。如您所见,0 号列车永远无法进入主轨道。我一定是误解了线程是如何被条件变量唤醒并陷入死锁的。我错过了什么?
是的,你对pthread_cond_wait
有点误解。 man page 表示:
The pthread_cond_timedwait() and pthread_cond_wait() functions shall
block on a condition variable. They shall be called with mutex locked
by the calling thread or undefined behavior results.
These functions atomically release mutex and cause the calling thread
to block on the condition variable cond;
所以你需要在调用pthread_cond_wait
之前锁定。也就是说,您的代码应该是:
/* If the main track is currently in use, wait for it to become available */
pthread_mutex_lock(&main_track_mutex); /* SHOULD LOCK HERE */
while(main_track_status)
pthread_cond_wait(&main_track_condition_var, &main_track_mutex);
/* Use the main track */
//pthread_mutex_lock(&main_track_mutex); /* INCORRECT */
//<..SNIP..>
pthread_mutex_unlock(&main_track_mutex);
pthread_cond_signal(&main_track_condition_var);
我正在创建火车站模拟。从文件中读取列车信息。文件的每一行代表一列火车,每列火车都有自己的线程。火车站的主轨道一次只能容纳1列火车。这是我的代码:
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <string.h>
#include <readline/readline.h>
#include <unistd.h>
pthread_mutex_t main_track_mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t main_track_condition_var = PTHREAD_COND_INITIALIZER;
int main_track_status = 0;
void *train_function(void *args) {
/* Parse train information */
int line_number = atoi(strtok(args, ":,"));
char *priority_direction = strtok(NULL,":,");
int loading_time = atoi(strtok(NULL, ":,"));
int crossing_time = atoi(strtok(NULL, ":,"));
/* Load train */
sleep(loading_time/10);
printf("Train %d is ready to go %s\n",line_number,priority_direction);
/* If the main track is currently in use, wait for it to become available */
while(main_track_status)
pthread_cond_wait(&main_track_condition_var, &main_track_mutex);
/* Use the main track */
pthread_mutex_lock(&main_track_mutex);
main_track_status = 1;
printf("Train %d is ON the main track going %s\n",line_number,priority_direction);
sleep(crossing_time/10);
main_track_status = 0;
/* Notify other trains main track is empty */
pthread_mutex_unlock(&main_track_mutex);
pthread_cond_signal(&main_track_condition_var);
printf("Train %d is OFF the main track after going %s\n",line_number,priority_direction);
pthread_exit(0);
}
int main() {
FILE *ptr_file;
char buff[10];
int train_count = 0;
char *train;
char line[15];
pthread_t trains[3];
ptr_file = fopen("./trains.txt", "r");
if (!ptr_file)
{
perror("fopen for trains.txt failed");
exit(EXIT_FAILURE);
}
/* Create train for each line of file */
while (fgets(buff,10, ptr_file)!=NULL) {
train = (char*)malloc(10 * sizeof(char));
/* Include line number from file in train information */
sprintf(line, "%d:", train_count);
strcat(line, buff);
strcpy(train, line);
if(pthread_create(&trains[train_count], NULL, &train_function, (void *) train))
{
perror("pthread create failed");
exit(EXIT_FAILURE);
}
train_count++;
}
fclose(ptr_file);
/* Wait for all trains to leave the station */
for (int x = 0; x < train_count; x++) {
pthread_join(trains[x], NULL);
}
free(train);
exit(EXIT_SUCCESS);
}
火车输入文件:
e:10,6
W:5,7
E:3,10
程序的输出是:
Train 1 is ready to go W
Train 1 is ON the main track going W
Train 1 is OFF the main track after going W
Train 2 is ready to go E
Train 2 is ON the main track going E
Train 0 is ready to go e
Train 2 is OFF the main track after going E
我认为我的错误在于train_function。如您所见,0 号列车永远无法进入主轨道。我一定是误解了线程是如何被条件变量唤醒并陷入死锁的。我错过了什么?
是的,你对pthread_cond_wait
有点误解。 man page 表示:
The pthread_cond_timedwait() and pthread_cond_wait() functions shall block on a condition variable. They shall be called with mutex locked by the calling thread or undefined behavior results.
These functions atomically release mutex and cause the calling thread to block on the condition variable cond;
所以你需要在调用pthread_cond_wait
之前锁定。也就是说,您的代码应该是:
/* If the main track is currently in use, wait for it to become available */
pthread_mutex_lock(&main_track_mutex); /* SHOULD LOCK HERE */
while(main_track_status)
pthread_cond_wait(&main_track_condition_var, &main_track_mutex);
/* Use the main track */
//pthread_mutex_lock(&main_track_mutex); /* INCORRECT */
//<..SNIP..>
pthread_mutex_unlock(&main_track_mutex);
pthread_cond_signal(&main_track_condition_var);