gpt4 book ai didi

c - 多线程 C 程序无法使用参数运行

转载 作者:行者123 更新时间:2023-11-30 17:44:38 25 4
gpt4 key购买 nike

我正在用 C 编写一个程序。这是一个多线程程序,应该有一个线程(读取器)读取文件中一行上的两个 int,然后打印它们。另一个线程必须添加整数,然后打印结果。

它们只允许与信号进行通信,不允许使用互斥体、信号量或条件变量。

我遇到的问题是,当我使用 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;
}

最佳答案

您有两个主要问题:

(1) 混合 killpthread_killkill 会将信号发送到进程,等待该信号的线程收到该信号的机会是随机的。 pthread_kill 将其定向到特定线程。因此,当读取器线程向进程发送 kill sigusr1 时,读取器和主进程都在等待它,并且读取器每次都会得到它,从而抛出序列。通过将其更改为pthread_kill,它可以被定向到正确的线程。

(2) eof 逻辑已关闭。 reader 会点击 eof 并立即循环并等待,从不通知 main 事情已经完成。

这是你的 95% 的代码,所以我不会因为把它交给你而感到内疚,但你仍然需要仔细检查它,查看更改并清理它

#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;
pthread_t tid;
unsigned int seed;
} pair_t;

static void cleanExitReader()
{
printf("Goodbye from Reader Thread\n");
}

static void cleanExitCalc()
{
printf("Goodbye from Calculator Thread\n");
}

//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 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.
int result = sigwait(&listenSigs, &listenSigs_r);
if(result == 0)
printf("reader sigwait got signal: %d\n", listenSigs_r);

if(fscanf(numPair->fp, "%d %d", &numPair->num0, &numPair->num1) == EOF)
{
pthread_kill(numPair->tid, SIGUSR1);
continue;
}
else
{
//usleep(rand_r(&seed) % 10000);
printf("read values: %d %d\n", numPair->num0, numPair->num1);
pthread_kill(numPair->tid, 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 a sigset for sigwait to wait for.
sigset_t listenSigs;
sigemptyset(&listenSigs);
sigaddset(&listenSigs, SIGUSR2);
int listenSigs_r;

//Adding loop
while(1)
{
int result = sigwait(&listenSigs, &listenSigs_r);
if(result == 0)
printf("calc sigwait got signal: %d\n", listenSigs_r);

int i = numPair->num0 + numPair->num1;
//usleep(rand_r(&seed) % 10000);
printf("result of calc = %d\n", i);
pthread_kill(numPair->tid, SIGUSR2);
}

pthread_cleanup_pop(1);
}


//Main
int main (int argc, char *argv[])
{
//Declare threads, file pointer, tid and struct
pthread_t r, c;
FILE *fp;
//pid_t pid;
pthread_t tid;
pair_t numbers;

//Exit if no argument given
if(argc < 2)
{
printf("Please enter one file as an argument\n");
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();
tid = pthread_self();

//Assign values to struct tid and fp
numbers.tid = tid;
numbers.fp = fp;


//Blocking SIGUSR1 and SIGUSR2
sigset_t blockSigs;
sigaddset(&blockSigs, SIGUSR1);
sigaddset(&blockSigs, SIGUSR2);
pthread_sigmask(SIG_BLOCK, &blockSigs, NULL);

//Create threads here so they inherit sigmasks
pthread_create(&r, NULL, readerThread, (void *)&numbers);
pthread_create(&c, NULL, calcThread, (void *)&numbers);

//Set up the listening set for SIGUSR1/2
sigset_t listenSigs;
sigemptyset(&listenSigs);
sigaddset(&listenSigs, SIGUSR1);
sigaddset(&listenSigs, SIGUSR2);
int listenSigs_r;

while(1)
{
if(feof(fp))
break;

pthread_kill(r, SIGUSR1);
int result = sigwait(&listenSigs, &listenSigs_r);
if(result == 0)
printf("main 1 sigwait got signal: %d\n", listenSigs_r);


pthread_kill(c, SIGUSR2);
sigwait(&listenSigs, &listenSigs_r);
if(result == 0)
printf("main 2 sigwait got signal: %d\n", listenSigs_r);

printf("\n\n"); //easier to read

}

pthread_cancel(r);
pthread_cancel(c);
pthread_join(r, NULL);
pthread_join(c, NULL);

fclose(fp);
return 0;
}

关于c - 多线程 C 程序无法使用参数运行,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19907671/

25 4 0
文章推荐: c# - 您可以在 Entity Framework 导航属性上使用投影吗?
文章推荐: javascript - 删除 HTML 表格行
文章推荐: javascript - 未捕获的类型错误 : Object # has no method 'Jcrop'