1

我在一个线程中生成“事件”结构,并以几秒的间隔将它们发送回主线程。自然是不行的。我有两个问题:

  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

测试.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读入结构,就像使用 write 一样。

还有其他几点:首先实际上是发送指针的地址,而不是实际的指针。其次,您不必动态分配结构,只需在堆栈上分配并发送结构即可。

于 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 回答