2015-09-06 89 views
1

我在後端線程中使用libevent來運行hiredis並訂閱遠程redis數據庫。訂閱作品寄望用簡單的例子從另一個SO問題:如何通知運行libevent的線程應該採取一些措施?

Hiredis waiting for message

然而,爲了避免競爭條件是不平凡的主線程添加訂閱。爲了達到這個目的,我創建了一個std::vector<std::string>對象,其中包含後端應該訂閱的任何關鍵字符串。從這個向量讀/寫是通過一個互斥體執行的。

但是,如何通知後端添加了一些訂閱?目前我使用的定時器設置爲一個非常低的分辨率:

void Client::fireAndRequeueTimer(int fd, short e, void* arg)       
{                     
    Client* client = reinterpret_cast<Client*>(arg); // the client handles the subscription to redis (via hiredis/libevent)                      
    if (client->mDisconnect)        
     return; // the main thread wants us to exit, so we don't recreate the timer 

    event* ev = &client->mTimerEvent; // some timer event object we created 
    timeval tv;                  
    tv.tv_sec = 0;                 
    tv.tv_usec = 1000; // 1ms              

    evtimer_add(ev, &tv); 

    // mPendingSubscriptions is an std::vector of strings, which contain the keys that we should add subscriptions to. 
    if (client->mPendingSubscriptions.size())          
    {                    
     std::unique_lock<std::mutex> lock(client->mSubscriptionsMutex);    

     do                   
     {                   
      redisAsyncCommand(              
       client->mContext,             
       Client::subCallback,             
       (char*)"sub",              
       "SUBSCRIBE %s",              
       client->mPendingSubscriptions.back().c_str());      

      client->mPendingSubscriptions.pop_back();        
     }                   
     while (client->mPendingSubscriptions.size());        
    }                    
}                     

(請注意,我用libevent 1.4.x這樣的功能,如EV_PERSIST不存在的,我必須重新在每個事件定時器)。

雖然上述作品,我很不滿意的話,原因如下:

  1. 它放置在後端不必要的壓力不斷輪詢載體。
  2. 讀者很難沒有廣泛的評論
  3. 它很慢;這個定時器會爲訂閱一個事件增加多達1ms的時間。這可能很重要,也可能不會,但無論如何,這是浪費時間。

是否有這個問題,將的libevent 1.4.x範圍內解決這些問題的任何溶液?

+0

不確定libevent是否使用pthreads?如果是這樣,你可以使用一個信號,例如SIGHUP,並設置pthread的sigmask,所以只有你的後端線程會接受信號? –

回答

0

個人而言,我傾向於讓目標線程將eventfd(或類似構造)添加到其事件隊列中。

eventfd可以安全地通知任何其他線程,並導致目標線程調用關聯的事件處理程序。

這樣,您不必擔心正確鎖定libevent結構的絕對最小值,因爲OS會爲您處理這些問題。

注意:eventfd在OSX上不可用,但只要您不需要極高的事件率就可以使用管道輕鬆模擬。

+0

這聽起來像我所需要的。我猜我需要使用'event_set(&event,fd,EV_READ,fn,data)',但我該如何獲得'fd'和b)「touch」fd來觸發事件? – arman

+0

我應該澄清;我追求的是儘可能便攜的解決方案,所以我想盡可能避免系統調用。 – arman

+0

有'evutil_socketpair'應該創建一個類似的解決方案,我承認它從來沒有嘗試過。 –

相關問題