2013-02-27 1 views
1

Я генерирую «события» в одном потоке и отправляю их обратно в основной поток через несколько секунд. Естественно, это не работает правильно. У меня есть два вопроса:Создание структур с одним потоком и получение в другом потоке с селектором

  1. Почему я получаю сообщения, полученные от bazillion в моем цикле выбора? Нужно ли мне читать из трубы, поэтому дескриптор файла больше не говорит, что там есть вещи?
  2. Как я могу получить ссылку на структуру из трубы?

Желаемая Выход:

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

Acutal Выход:

$ ... 
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); 
} 
+0

+1 только для «Естественно, это не работает правильно» :) –

ответ

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); 
} 
0

select сообщает только, что имеются данные. У вас должно быть read данных, чтобы получить его от дескриптора. Я бы также рекомендовал вам добавить немного информации к вашему отладку (отметка времени как минимум), чтобы вы могли видеть широту создания данных :)

1
  1. Да, вы должны прочитать из трубы или он будет навсегда оставаться читаемым.
  2. Используйте read для чтения в структуру, так же, как вы делаете с записью.

Есть еще несколько пунктов: сначала на самом деле отправляются адрес указателя, а не фактический указатель. Во-вторых, вам не нужно динамически выделять структуру, просто выделите ее в стек и отправьте структуру.

Смежные вопросы