2012-12-02 52 views
0
#include "cs241.c" 

#define THREAD_COUNT 10 

int list_s; 
int connections[THREAD_COUNT]; 
char space[THREAD_COUNT]; 

int done = 0; 

pthread_mutex_t muxlock = PTHREAD_MUTEX_INITIALIZER; 

int *numbers; 
int numbers_count; 

void *listener(void *arg) { 
    int n = *(int *) arg; 

    FILE *f = fdopen(connections[n], "r"); 
    if (f == NULL) 
     printf("Could not open file\n"); 
    char *line = NULL; 
    size_t *len = malloc(sizeof(int)); 
    while(getline(&line, len, f) != -1) { 
     printf("%s", line); 
     if (strcmp("END", line) == 0) { 
          pthread_mutex_lock(&muxlock); 
      done = 1; 
      pthread_mutex_unlock(&muxlock);      
     } 
    } 

    space[n] = 't'; 
    fclose(f); 
    free(len); 
    close(connections[n]); 
    return NULL; 
} 

void initialize() { 
    int n; 
    for (n = 0; n < THREAD_COUNT; n++) { 
     space[n] = 't'; 
    } 
} 

int check() { 
    int index; 
    for (index = 0; index < THREAD_COUNT; index++) { 
     if (space[index] == 't') { 
      space[index] = 'f'; 
      return index; 
     } 
    } 
    return 0; 
} 

int main(int argc, char *argv[]) { 
    int port = 0; 
    int binder; 
    int lis; 
    int i = 0; 
    int *j = malloc(sizeof(int)); 
    initialize(); 
    pthread_t threads[THREAD_COUNT]; 

    if ((argc != 2) || (sscanf(argv[1], "%d", &port) != 1)) { 
     fprintf(stderr, "Usage: %s [PORT]\n", argv[0]); 
     exit(1); 
    } 

    if (port < 1024) { 
     fprintf(stderr, "Port must be greater than 1024\n"); 
     exit(1); 
    } 

    // set the initial conditions for the numbers array. 
    numbers = malloc(sizeof(int)); 
    numbers_count = 0; 

    struct sockaddr_in servaddr; // socket address structure 
    // set all bytes in socket address structure to zero, and fill in the relevant data members 
    memset(&servaddr, 0, sizeof(servaddr)); 
    servaddr.sin_family = AF_INET; 
    servaddr.sin_addr.s_addr = htonl(INADDR_ANY); 
    servaddr.sin_port = htons(port); 

    list_s = socket(AF_INET, SOCK_STREAM, 0); 
    if (list_s < 0) { 
     printf("Could not create socket\n"); 
     exit(EXIT_FAILURE); 
    } 
    binder = bind(list_s, (struct sockaddr *) &servaddr, sizeof(servaddr)); 
    if (binder < 0) { 
     printf("Could not bind socket\n"); 
     exit(EXIT_FAILURE); 
    } 
    lis = listen(list_s, SOMAXCONN); 
    if (lis < 0) { 
     printf("Could not listen on socket\n"); 
     exit(EXIT_FAILURE); 
    } 
    SET_NON_BLOCKING(list_s); 
    while (done != 1) { 
     connections[i] = accept(list_s, NULL, NULL); 
     if (connections[i] < 0) { 
      if ((errno == EAGAIN) || (errno == EWOULDBLOCK)) 
       continue; 
      printf("Could not accept connection\n"); 
      exit(EXIT_FAILURE); 
     } 
     i = check(); 
     *j = i; 
        SET_BLOCKING(list_s); 
     pthread_create(&threads[i], NULL, listener, j); 
    } 

    // Verify the array. 
    //verify(numbers, numbers_count); 

    free(j); 
    close(list_s); 

    exit(EXIT_SUCCESS); 

} 

所以我有一個while循環在我的main(),它應該退出時,'完成'= 1。這是由偵聽器()設置,當它收到'結束'。第一個問題是,當我在第一次迭代中發送'END'時,只有在發送另一個'END'後,while循環纔會退出。POSIX線程在C插座

我有兩個宏SET_NON_BLOCKING和SET_BLOCKING在另一個文件中用於解鎖和阻塞套接字,因此如果沒有連接,它會等待連接。接下來的問題是,當我不使用這些宏時,listener()中的getline()無法讀取從流輸出的所有內容。當我使用它們時,它根本無法打開流。

我認爲一些問題在於將'j'傳遞給線程,因爲當第二個線程啓動時,它會在第一個線程可以讀取之前覆蓋'j'。然而,我已經在這裏呆了幾天,並且無法到達任何地方。任何幫助將不勝感激。謝謝!

另外我想問一下,我的套接字阻塞和線程鎖定是否在正確的位置?

回答

1

您可能必須發送END兩次,因爲您的主線程在產生偵聽器線程後立即在accept()上阻塞。由於其在accept()上被阻止,因此無法看到done == 1

您可以通過保持非阻塞模式來解決此問題。如果你這樣做,你可能想睡覺以避免在緊密的環路中旋轉。另一種方法是發送一個信號喚醒接收,使其設置EINTR。

在將連接索引傳遞給偵聽器線程方面,您可能正確地認爲線程之間的競爭覆蓋了該值。由於int將需要與void *相同或更少的字節,因此您可以直接通過int。例如:

pthread_create(&threads[i], NULL, listener, (void *)i); 

然後在聽衆:

int n = (int)arg; 

這是怎樣的一個黑客。更完整的解決方案是使用malloc爲每個線程分配單獨的參數結構。監聽器線程將負責釋放參數。

struct params *p = args; 
if (p == NULL) { 
    // handle error 
    return NULL; 
} 
int n = p->index; 
free(p); 
0

似乎有是錯誤的,你是如何管理connections[]space[]陣列不少東西:

  • 您接受一個連接到

    struct params *p = malloc(sizeof(struct params)); 
    p.index = i; 
    
    pthread_create(&threads[i], NULL, listener, p); 
    
    在聽衆

    然後connections[i],但您傳遞給listener線程的i是由check()返回的線程 - 可能是一個完全不同的i

  • 每個線程都獲得一個線程參數的相同地址 - j僅被分配一次,並且每個線程創建都使用相同的分配。如果兩個或更多線程幾乎同時開始運行,您將失去應傳遞給其中一些的索引。
  • 當它完成時,listener標記連接爲可用(我假設這是space[n] = 't';的意圖),但隨後使用connections[n]關閉連接。這些都沒有與任何同步執行。

一些其他意見:

  • 爲什麼在世界上你是動態分配len
  • donemain()while循環檢查應當由一個互斥量來保護
  • 我不太確定的協議是什麼,正在傳輸的數據,但由於您使用的getline()我以爲這是一組以換行符結尾的行。在這種情況下,請記住getline()文檔中的一些信息:「緩衝區以空字符結尾,幷包含換行符,如果找到的話」。如果"END"行包含換行符,則strcmp("END",line)不會返回0
+0

「size_t * len = malloc(sizeof(int));」 – loreb

+0

@loreb:我不確定你的評論指出了什麼。然而,分配是錯誤的('int'可能與size_t不一樣),但更重要的是它是不必要的。只需要'size_t len;'並傳遞len的地址:'getline(&line,&len,f)' –