1

1つのスレッドで「イベント」構造体を生成し、数秒間隔でメインスレッドに送り返しています。当然、それは正しく機能しません。2つの質問があります:

  1. 選択ループで何億ものイベント受信メッセージを受け取るのはなぜですか?ファイル記述子がそこに何かがあると言わないように、パイプから読み取る必要がありますか?
  2. 構造体への参照をパイプから引き出すにはどうすればよいですか?

必要な出力:

$ ...
Writing event 1 to pipe
Received event on pipe
Writing event 2 to pipe
Received event on pipe

実際の出力:

$ ...
Received event on pipe
Received event on pipe
Received event on pipe
Received event on pipe
Received event on pipe
Received event on pipe
Received event on pipe
Received event on pipe
Received event on pipe
Received event on pipe
Received event on pipe
Received event o^C

GCCコマンド:

gcc -o test test.c

test.c:

/* Simple example with two threads and a pipe. One thread writes structs to a 
   pipe every few seconds; the other reads the structs, prints out their info
   and then frees the structs
 */

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <pthread.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/select.h>

void mywait(int timeInSec);

// The events
typedef struct event {
    int id;
    int data;
} event_t;

int id = 0;
int pipefd[2];

void* pump(void *arg) { // Generates events

    for (;;)
    {
        mywait(1); // sleep thread

        printf("writing event #%i to pipe\n", id);

        // generate event
        event_t *event;
        event = malloc(sizeof(*event));
        memset(event, 0, sizeof(*event));
        event->id = id++;

        // write event to pipe
        write(pipefd[1], &event, sizeof(event));

        // NOTE: Free event in other thread
    }
}

int main (int argc, char **argv)
{
    printf("Starting pipe_test.c\n");

    // 1. Create a pipe
    pipe(pipefd);

    // 2. Create thread to pump events into pipe
    pthread_t tid;
    if (pthread_create( &tid, NULL, pump, NULL) != 0) {
        perror("pthread_create:pump");
        exit(-1);
    }

    // 3. Set up selector in main thread to read events off pipe
    int z;
    fd_set readfds; //readable file descriptor
    int selectmax;
    selectmax = pipefd[0] + 1;
    for (;;)
    {
        // Initialize selector
        FD_ZERO( &readfds );
        FD_SET( pipefd[0], &readfds );
        z = select( selectmax, &readfds, NULL, NULL, NULL );

        if( z < 0 ) {
            printf( "select() failed\n");
            // close( pipefd ); //???
            return 1;
        } else {
            if( FD_ISSET( pipefd[0], &readfds ) ) {
                printf("Received event on pipe\n"); // I get a shitton of these

                // Get the pointer to the event struct from the pipe
                // TODO: GOOD WAY TO DO THIS?

                // Free the struct
                // TODO
            }
        }
    }

    return 0;
}

// From http://somethingswhichidintknow.blogspot.com/2009/09/sleep-in-pthread.html
pthread_mutex_t fakeMutex = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t fakeCond = PTHREAD_COND_INITIALIZER;

void mywait(int timeInSec)
{
    struct timespec timeToWait;
    struct timeval now;
    int rt;
    gettimeofday(&now,NULL);

    timeToWait.tv_sec = now.tv_sec + timeInSec;
    timeToWait.tv_nsec = now.tv_usec*1000;

    pthread_mutex_lock(&fakeMutex);
    rt = pthread_cond_timedwait(&fakeCond, &fakeMutex, &timeToWait);
    pthread_mutex_unlock(&fakeMutex);
}
4

3 に答える 3

1
  1. はい、パイプから読み取る必要があります。そうしないと、いつまでも読み取り可能になります。
  2. read書き込みの場合と同じように、構造体への読み取りに使用します。

他にもいくつかのポイントがあります。最初は、実際のポインタではなく、実際にポインタのアドレスを送信することです。次に、構造を動的に割り当てる必要はありません。スタックに割り当てて構造を送信するだけです。

于 2013-02-27T12:59:10.990 に答える
1

他の人が指摘したように、実際にデータを読み取る必要があります。また、ポインタ(つまり)だけでなく、構造全体にメモリを割り当てる必要があることにも注意してくださいevent = malloc(sizeof(event_t));

/* Simple example with two threads and a pipe. One thread writes structs to a 
   pipe every few seconds; the other reads the structs, prints out their info
   and then frees the structs
 */

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <pthread.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/time.h>
#include <sys/select.h>

void mywait(int timeInSec);

// The events
typedef struct event {
    int id;
    int data;
} event_t;

int id = 0;
int pipefd[2];

void* pump(void *arg) { // Generates events

    for (;;)
    {
        printf("writing event #%i to pipe\n", id);

        // generate event
        event_t *event;
        event = malloc(sizeof(event_t));
        memset(event, 0, sizeof(event_t));
        event->id = id++;

        // write event to pipe
        int nbytes = write(pipefd[1], &event, sizeof(event_t*));
        //printf("written %d bytes.\n", nbytes);

        // NOTE: Free event in other thread
        mywait(1); // sleep thread
    }
}

int main (int argc, char **argv)
{
    printf("Starting pipe_test.c\n");

    // 1. Create a pipe
    pipe(pipefd);

    // 2. Create thread to pump events into pipe
    pthread_t tid;
    if (pthread_create( &tid, NULL, pump, NULL) != 0) {
        perror("pthread_create:pump");
        exit(-1);
    }

    // 3. Set up selector in main thread to read events off pipe
    int z;
    fd_set readfds; //readable file descriptor
    int selectmax;
    selectmax = pipefd[0] + 1;
    for (;;)
    {
        // Initialize selector
        FD_ZERO( &readfds );
        FD_SET( pipefd[0], &readfds );
        z = select( selectmax, &readfds, NULL, NULL, NULL );

        if( z < 0 ) {
            printf( "select() failed\n");
            // close( pipefd ); //???
            return 1;
        } else {
            if( FD_ISSET( pipefd[0], &readfds ) ) {
                printf("Received event on pipe\n"); // I get a shitton of these

                // Get the pointer to the event struct from the pipe
                event_t* received_event = NULL;
                int nbytes = read(pipefd[0], &received_event, sizeof(event_t*));
                printf("read %d bytes\n", nbytes);
                if (nbytes > 0)
                    printf("Event id: %d\n", received_event->id);

                // Free the struct
                free(received_event);
            }
        }

        mywait(1); // sleep thread
    }

    return 0;
}

// From http://somethingswhichidintknow.blogspot.com/
// 2009/09/sleep-in-pthread.html
pthread_mutex_t fakeMutex = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t fakeCond = PTHREAD_COND_INITIALIZER;

void mywait(int timeInSec)
{
    struct timespec timeToWait;
    struct timeval now;
    int rt;
    gettimeofday(&now,NULL);

    timeToWait.tv_sec = now.tv_sec + timeInSec;
    timeToWait.tv_nsec = now.tv_usec*1000;

    pthread_mutex_lock(&fakeMutex);
    rt = pthread_cond_timedwait(&fakeCond, &fakeMutex, &timeToWait);
    pthread_mutex_unlock(&fakeMutex);
}
于 2013-02-27T13:42:33.467 に答える
0

select利用可能なデータがあることだけを伝えます。read記述子からデータを取得するには、データを使用する必要があります。また、データ作成の幅を確認できるように、デバッグに少しの情報(少なくともタイムスタンプ)を追加することをお勧めします:)

于 2013-02-27T12:58:44.287 に答える