2015-06-27 13 views
0

我當前的應用程序是旨在複製的http://sprunge.us/行爲C語言編寫的一個玩具Web服務(通過HTTP POST取數據,將其存儲到磁盤,返回客戶端數據的網址 - 也提供以前根據請求存儲的數據)。從回調將數據傳輸到/從/到一個工作線程

應用程序的結構是這樣,一個線程池進行實例化的工作線程(只是一個函數指針採用一個void *參數)和插座被打開來聽傳入的連接。該程序的主循環包括一個sock = accept(...)調用,然後是一個pool_add_task(worker_function_parse_http, sock),以便能夠快速處理請求。 的parse_http工人解析傳入請求,要麼增加了另一個任務的工作隊列,用於存儲所述數據(POST)或服務於先前存儲的數據(GET)。

我使用這種方法的問題源於使用回調設計返回分析數據的http-parser庫(我查看的所有http解析器均使用此樣式)。我遇到的問題是這樣的:

parse_http工人:從接受套接字

  1. 緩衝區數據(函數的唯一參數,在此階段)
  2. 設置一個http-parser對象按照其API,並完成設置回調函數,以便在完成解析URL或BODY或其他內容時調用它。 (這些功能是由http-parser LIB所限定的固定式簽名的,具有指向包含相關的呼叫所解析的數據的緩衝器,所以無法在我自己的變量傳遞和解決問題的方式。這些功能也返回一個狀態碼給http解析器,所以我也不能使用返回值。從解析器中獲取數據供以後使用的建議方法是在回調期間將其複製到全局變量中 - 有多個線程。)

  3. 執行上所緩衝的套接字數據解析器。在這個階段,解析器需要在解析緩衝區的不同部分時調用其設置的回調函數。該回調提供了與每個回調有關的解析數據(例如提供給body_parsed回調函數的BODY段)。

  4. 好了,這就是問題的說明。解析器已執行,但我無法訪問解析的數據。這裏是我添加一個新任務到隊列的工作人員功能來存儲接收到的身體數據或另一個來處理以前存儲的數據的GET請求。這些函數需要提供解析後的信息(POST數據或GET url)以及接受的套接字,以便現在委派的工作可以響應請求並關閉連接。

當然,這個問題顯而易見的解決辦法很簡單,就是不要使用異步實踐這個線程池模式,但我想知道,現在和以後,如何更好地解決這個問題。

如何從這些回調中將解析的數據返回給工作線程函數。我考慮過簡單地讓我的on_url_parsedon_body_parsed執行應用程序的其餘部分(存儲和檢索數據),但當然,我不再有客戶端的套接字在這些上下文中進行響應。

如果需要,我可以將源代碼發佈到項目中,當我有機會時。

編輯:事實證明,可以從該特定http分析器庫的回調中訪問用戶定義的void *,因爲回調被傳遞給調用者(分析器對象)的引用,可定義的數據字段。

回答

1

一個設計良好的回調接口將爲您提供給解析器一個void *,它會在調用它們時將它傳遞給每個回調函數。您提供的回調函數知道它指向的對象類型(因爲您提供了數據指針和函數指針),所以它們可以投射並正確地解引用它。除了其他優點外,通過這種方式,您可以提供回調函數來訪問啓動解析的函數的局部變量,而不必依賴全局變量。

如果您正在使用的解析器庫沒有這樣的功能(並且您不想切換到更好設計的功能),那麼您可以使用線程本地存儲而不是全局變量。你將如何做到這一點取決於你的線程庫和編譯器,或者你可以通過使用線程標識符作爲鍵來指定某些全局數據結構(例如散列表)中的線程特定槽。

+0

感謝您的輸入。我認爲這將是一個可能的解決方案,但我不確定是否過於複雜,試圖讓線程/異步的東西在一起玩,所以很高興聽到別人的聲音。 我確實找到了一個功能解決方案,這個功能在這個特定的解析器的API中沒有很好的記錄,所以這就是我會先嚐試的。 – lberezy

相關問題