使用libevent編寫多線程服務端
一、設計框架:
1)主線程監聽連接各種事件,創建多個工作線程處理具體業務
2)收到連接時創建對象管理,並綁定到一個線程
3)主線程監聽到一個讀事件,將該連接添加到所綁定的線程的處理隊列
4)工作線程一次取出隊列元素,從bufferevent讀取數據,並處理
二、、設置bufferevent爲多線程安全(也就是每次讀寫bufferevent都是上鎖的)
1)設置多線程支持
#ifdef WIN32
evthread_use_windows_threads();
#else
evthread_use_pthreads();
#endif
2)創建bufferevent時加上BEV_OPT_THREADSAFE標誌
struct bufferevent *bev = NULL;
bev = bufferevent_socket_new(base, fd, BEV_OPT_CLOSE_ON_FREE | BEV_OPT_THREADSAFE);
3)此後使用bufferevent緩存就是線程安全的
當然在自己的代碼中也可以使用bufferevent的鎖
bufferevent_lock(bev);
/*............中間這部分已經加鎖...........*/
bufferevent_unlock(bev);
三、使用智能指針(std::shared_ptr<type> nodeptr(new type))管理連接對象
1)原因:
創建了一個對象來管理一個連接(bufferevent),在多線程中,可能主線程監聽到斷開連接,這時就會刪除該對象,但是,此時可能工作線程中正通過對象對連接的數據進行處理,如果刪除了該對象,造成的後果很可能時段錯誤-程序崩潰。
2)因此:
收到連接時創建一個智能指針指向連接對象,並用容器保存。
收到連接讀事件時,將該連接對象的智能指針傳到工作線程的處理隊列。
線程取出智能指針後,通過該智能指針調用對象接口。
此時,及時主線程從容器中刪除了該智能指針,但是線程中正通過同一對象的智能指針調用對象,對象實際上就不會刪除,只有等待工作線程處理結束並跳出智能指針的棧範圍,連接對象纔會實際刪除。
如果工作線程處理完對象後,需要向連接寫數據,那麼一定要注意加鎖、加判斷條件,因爲此時可能連接已經斷開了。