2016-08-04 73 views
0

所以我有一個運行libev I/O循環和計時器循環的程序。當char數組遇到7000個字符或者定時器循環命中10秒時,它會轉到JSON POST一個在localhost上運行的服務。 I/O循環導致程序在空閒時使用差不多100%的CPU。libev循環在空閒時使用99%的CPU

此程序需要的任一1的argv的或0:

  • A 1使得程序僅處理一條線並退出。
  • 0使其等待輸入。

錯誤只發生在我們將它傳遞給0並讓它等待輸入時。

#include <stdio.h> 
#include <ev.h> 
#include <curl/curl.h> 
#include <json-c/json.h> 
#include <unistd.h> 

void curlPage(char url[], char message[]); 
void io_callback(EV_P_ ev_io *w_, int rev); 
void time_callback(EV_P_ ev_timer *w_, int rev); 

struct watcher 
{ 
    ev_io stdin_watcher; 
    ev_timer time_watcher; 
}; 

char lines[BUFSIZ]; 
char *argv1; 
char url[1024] = "http://127.0.0.1:"; 
char *end; 


int main(int argc, char *argv[]) { 
    struct ev_loop *loop; 
    struct watcher w; 

    if (!argv[1]) { 
     printf("YOU NEED A 1 OR 0 PARAMATER FOR THIS TO WORK!\n"); 
     exit(0); 
    } 
    else { 
     end = argv[1]; 
    } 
    argv1 = argv[2]; 

    if (argv[3]) { 
     strcat(url, argv[3]); 
    } 
    else { 
     strcat(url, "8888"); 
    } 

    loop = ev_default_loop(0); 

    ev_io_init(&w.stdin_watcher, io_callback, STDIN_FILENO, EV_READ); 
    ev_timer_init(&w.time_watcher, time_callback, 10, 0); 
    w.time_watcher.repeat=10; 
    ev_io_set(&w.stdin_watcher, STDIN_FILENO, EV_READ); 
    ev_io_start(loop, &w.stdin_watcher); 
    ev_timer_start(loop, &w.time_watcher); 

    ev_run(loop, 0); 

    return 0; 
} 

void time_callback(EV_P_ ev_timer *w_, int rev) { 
    if (strlen(lines)) { 
     curlPage(url, lines); 
     lines[0] = '\0'; 
    } 
    return; 
} 

void io_callback(EV_P_ ev_io *w_, int rev) { 
    struct watcher *w = (struct watcher *)w_; 

    char buf[BUFSIZ]; 
    char * resp; 

    resp = fgets(buf, sizeof buf, stdin); 
    if (resp != NULL) { 
     sprintf(lines, "%s %s", lines, buf); 
    } 


    if (strlen(lines) > 7000) { 
     curlPage(url, lines); 
     lines[0] = '\0'; 
    } 
    if (strcmp(end, "1") == 0) { 
     ev_io_stop(loop, w_); 
    } 
    return; 
} 

void curlPage(char url[], char message[]) { 
    CURL *curl; 
    CURLcode res; 
    json_object * jsonObj = json_object_new_object(); 
    char hostname[1024]; 

    gethostname(hostname, 1024); 
    struct curl_slist * headers=NULL; 
    headers = curl_slist_append(headers, "Accept: application/json"); 
    headers = curl_slist_append(headers, "Content-Type: application/json"); 
    headers = curl_slist_append(headers, "charsets: utf-8"); 

    curl = curl_easy_init(); 

    if(curl) { 

     if (hostname) { 
      json_object *jstring2 = json_object_new_string(hostname); 
      json_object_object_add(jsonObj, "hostname", jstring2); 
     } 
     if (argv1) { 
      json_object *jstring3 = json_object_new_string(argv1); 
      json_object_object_add(jsonObj, "tag", jstring3); 
     } 

     json_object *jstring = json_object_new_string(message); 
     json_object_object_add(jsonObj, "message", jstring); 

     curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "POST"); 
     curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers); 
     curl_easy_setopt(curl, CURLOPT_URL, url); 
     curl_easy_setopt(curl, CURLOPT_POSTFIELDS, json_object_get_string(jsonObj)); 

     res = curl_easy_perform(curl); 

     if(res != CURLE_OK) { 
      fprintf(stderr, "curl_easy_preform() failed: %s\n", curl_easy_strerror(res)); 
     } 
     curl_easy_cleanup(curl); 
    } 
    curl_global_cleanup(); 
    json_object_put(jsonObj); 

    // run only once. 
    if (strcmp(end, "1") == 0) { 
     exit(0); 
    } 
    return; 
} 

這裏是線程回溯和堆棧打印出來:

bt and stack print out

所以它看起來像I/O觀察者的第一個事件後得到連續的I/O事件。它正確地等待第一個事件,但之後消耗大部分CPU。我使用它是這樣的:

cat test.txt | logpush 0 & 

也許管道是造成這種情況?

所以我寫了一個測試程序,它只是一個簡單的libev I/O守望者:

#include <stdio.h> 
#include <ev.h> 
#include <unistd.h> 

void io_callback(EV_P_ ev_io *w_, int rev); 
void time_callback(EV_P_ ev_timer *w_, int rev); 

char lines[BUFSIZ]; 

int main(int argc, char *argv[]) { 
    struct ev_loop *loop; 
    struct ev_io stdin_watcher; 

    loop = ev_default_loop(0); 

    ev_io_init(&stdin_watcher, io_callback, STDIN_FILENO, EV_READ); 
    ev_io_set(&stdin_watcher, STDIN_FILENO, EV_READ); 
    ev_io_start(loop, &stdin_watcher); 

    ev_run(loop, 0); 

    return 0; 
} 

void io_callback(EV_P_ ev_io *w_, int rev) { 
    printf("callback hit\n"); 
    return; 
} 

的I/O回調被撞了數百次第二,即使沒有輸入,如果調用一個管,像這樣:

cat test.txt | ./test & 

也會發生這種情況時,一個進程我的程序中我管標準輸出。

這是我的問題的根本原因。

+0

如果(argv [2])== NULL,則if(argv [3])是UB。建議檢查預期範圍內的「argc」。 – chux

+0

'BUFSIZ'的價值是什麼? – chux

+0

'BUFSIZ是8192' –

回答

0

第二個片段的修改對管道起作用(至少:cat event.c | ./a.out)。這個問題似乎是沒有檢測到EOF,並繼續錘打文件描述符

#include <stdio.h> 
#include <ev.h> 
#include <unistd.h> 

void io_callback(EV_P_ ev_io *w_, int rev); 
void time_callback(EV_P_ ev_timer *w_, int rev); 


struct ev_loop *loop; /* made this global, because needed by the callback at closing time */ 

int main(int argc, char *argv[]) { 
    struct ev_io stdin_watcher; 

    loop = ev_default_loop(0); 

    ev_io_init(&stdin_watcher, io_callback, STDIN_FILENO, EV_READ); 
    ev_io_set(&stdin_watcher, STDIN_FILENO, EV_READ); 
    ev_io_start(loop, &stdin_watcher); 

    // ev_run(loop, 0); 
    ev_loop(loop, 0); 

    return 0; 
} 

void io_callback(EV_P_ ev_io *w_, int rev) { 
    int rc; 
    char ch; 

     /* replaced fgets() by read() */ 
    rc = read(STDIN_FILENO, &ch, 1); 

     /* diagnostic output should go to stderr */ 
    fprintf(stderr, "Callback hit, rc=%d, ch = %02x\n" 
     , rc, ch & 0xff 
     ); 
    if (rc == 0) ev_io_stop(loop, w_); 
    return; 
} 

- 和測試你可以使用下面的程序和管道輸出通過二進制,如:sh loop.sh | ./a.out

#!/bin/sh 
while true; do 
     date 
     sleep 5 
done 
+0

被讀取比fgets更有效率? –

+0

這不關乎效率。我想擺脫緩衝(至少不會被它弄糊塗)在內部,當它認爲需要一個充滿數據的緩衝區時,fgets()當然會調用read()。你當然應該用更大的緩衝區和第三個參數來調用read()。 – joop

+0

'謝謝你的幫助 –

0

sprintf(lines, "%s %s", lines, buf);是未定義的行爲。

int sprintf(char * restrict s, const char * restrict format, ...); 

restrict意味着sprintf()並不希望數據s點由別的功能訪問進行訪問。由於代碼通過liness和一個參數,代碼破壞了合同和未定義的行爲結果。可能的lines是簡單的增長和增長和增長。

相反

// sprintf(lines, "%s %s", lines, buf); 
strcat(lines, " "); 
strcat(lines, buf); 
// Other more time efficient code is possible 

像往常一樣,看出來了緩衝區溢出是一個問題。

代碼也可能有其他問題。

+0

取得許可證*聯繫* - > *合同*':)' –

+0

'將sprintf更改爲strcat,就像您建議的那樣不能解決問題。 ' –

+0

'即使我註釋掉了整個回調塊,並且只有返回它仍然使用90%的cpu。 ' –

相關問題