【发布时间】:2013-11-11 13:33:14
【问题描述】:
我正在为 C 中的一个程序而苦苦挣扎。它是一个多线程程序,它应该有一个线程(阅读器)读取文件中一行上的两个整数,然后打印它们。另一个线程必须添加整数,然后打印结果。
它们只允许与信号通信,不允许互斥体、信号量或条件变量。
我遇到的问题是,当我使用 numbers.txt 作为参数运行程序时,似乎什么也没有发生。我认为尝试打开文件时它会停止,但我不确定。
感谢任何人提供的任何帮助,谢谢。
编辑:用 strace 运行它,发生了什么:http://pastebin.com/DPf6RPKf
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <signal.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <pthread.h>
//Struct for numbers and file
typedef struct
{
int num0, num1;
FILE *fp;
pid_t *pid;
unsigned int seed;
} pair_t;
static void cleanExitReader()
{
printf("Goodbye from Reader Thread");
}
static void cleanExitCalc()
{
printf("Goodbye from Calculator Thread");
}
//Reader thread
static void *
readerThread(void *numPair_in)
{
//Install cleanup handler
pthread_cleanup_push(cleanExitReader, NULL);
//Cast numPair_in as the struct
pair_t * numPair;
numPair = (pair_t *)numPair_in;
unsigned int seed;
//Create sigset and block
sigset_t blockSigs;
sigaddset(&blockSigs, SIGUSR1);
sigaddset(&blockSigs, SIGUSR2);
pthread_sigmask(SIG_BLOCK, &blockSigs, NULL);
//Create a sigset for sigwait to listen for.
sigset_t listenSigs;
sigemptyset(&listenSigs);
sigaddset(&listenSigs, SIGUSR1);
int listenSigs_r;
//Reading loop
while(1)
{
//Wait for signal from main before starting.
sigwait(&listenSigs, &listenSigs_r);
if(fscanf(numPair->fp, "%d %d", &numPair->num0, &numPair->num1) == EOF)
continue;
usleep(rand_r(&seed) % 10000);
printf("%d %d", numPair->num0, numPair->num1);
kill(*numPair->pid, SIGUSR1);
}
pthread_cleanup_pop(1);
}
//Calculator thread
static void *
calcThread(void *numPair_in)
{
//Install cleanup handler
pthread_cleanup_push(cleanExitCalc, NULL);
unsigned int seed;
//Cast numPair_in as the struct
pair_t * numPair;
numPair = (pair_t *)numPair_in;
//Create sigset and block
sigset_t blockSigs;
sigaddset(&blockSigs, SIGUSR1);
sigaddset(&blockSigs, SIGUSR2);
pthread_sigmask(SIG_BLOCK, &blockSigs, NULL);
//Create a sigset for sigwait to wait for.
sigset_t listenSigs;
sigemptyset(&listenSigs);
sigaddset(&listenSigs, SIGUSR2);
int listenSigs_r;
//Adding loop
while(1)
{
sigwait(&listenSigs, &listenSigs_r);
if(feof(numPair->fp))
continue;
int i = numPair->num0 + numPair->num1;
usleep(rand_r(&seed) % 10000);
printf("%d", i);
kill(*numPair->pid, SIGUSR2);
}
pthread_cleanup_pop(1);
}
//Main
int main (int argc, char *argv[])
{
//Declare threads, file pointer, pid and struct
pthread_t r, c;
FILE *fp;
pid_t pid;
pair_t numbers;
//Exit if no argument given
if(argc < 2)
{
printf("Please enter one file as an argument");
return 1;
}
//Open file
fp = fopen(argv[1], "r");
//Exit if fp = null
if(fp == NULL)
{
perror("fopen");
return 1;
}
//Get the process ID of the program
pid = getpid();
//Assign values to struct pid and fp
numbers.pid = &pid;
numbers.fp = fp;
//Blocking SIGUSR1 and SIGUSR2
sigset_t blockSigs;
sigaddset(&blockSigs, SIGUSR1);
sigaddset(&blockSigs, SIGUSR2);
pthread_sigmask(SIG_BLOCK, &blockSigs, NULL);
//Set up the listening set for SIGUSR1/2
sigset_t listenSigs;
sigemptyset(&listenSigs);
sigaddset(&listenSigs, SIGUSR1);
sigaddset(&listenSigs, SIGUSR2);
int listenSigs_r;
//Create threads here so they inherit sigmasks
pthread_create(&r, NULL, readerThread, (void *)&numbers);
pthread_create(&c, NULL, calcThread, (void *)&numbers);
while(1)
{
if(feof(fp))
break;
pthread_kill(r, SIGUSR1);
sigwait(&listenSigs, &listenSigs_r);
pthread_kill(c, SIGUSR2);
sigwait(&listenSigs, &listenSigs_r);
}
pthread_cancel(r);
pthread_cancel(c);
pthread_join(r, NULL);
pthread_join(c, NULL);
fclose(fp);
return 0;
}
【问题讨论】:
-
在调试器中运行,在一个线程中设置断点(从阅读器线程开始)并逐行执行以确保其正常工作。然后对另一个线程执行相同的操作。此外,在信号处理程序中放置断点,这样您就会知道它们也可以工作。
-
代码未初始化(emtpy)用于阻塞信号的
sigset_t变量。 -
另外,对
rand_r的两次调用的种子值也未初始化。 -
对
usleep的调用无论如何都是多余的。乍一看,这主要是一个设计问题。我看不出 main 中出现kill循环的任何原因。流程似乎应该是:(1)阅读器循环(读取值,信号计算,等待并退出 eof 上的线程;(2)主加入阅读器,取消计算线程。 -
Duck:usleep调用在赋值规范中被要求,main负责控制程序的流程。
标签: c multithreading unix pthreads posix