0

私は C のプログラムに苦労しています。これは、1 つのスレッド (リーダー) がファイル内の行にある 2 つの int を読み取り、それらを出力することになっているマルチスレッド プログラムです。もう一方のスレッドは、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;
}
4

1 に答える 1

0

2 つの主な問題がありました。

(1)混合killおよびpthread_killkillプロセスにシグナルを送信し、それを待機しているスレッドがシグナルを取得する可能性はランダムです。 pthread_kill特定のスレッドに誘導します。そのため、リーダー スレッドkill sigusr1がプロセスに a を送信すると、リーダーとメインの両方がそれを待っていて、リーダーは毎回それを取得するため、シーケンスがスローされます。それを変更することpthread_killで、適切なスレッドに向けることができます。

(2)eofロジックがオフでした。リーダーは、ヒットするeofとすぐにループして待機し、メインに処理が完了したことを通知しません。

これは 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;
}
于 2013-11-11T19:16:28.690 に答える