多線程同時操做一個epoll_fd

爲何選擇多線程?而不是多進程?

比起多進程來講,線程間通訊簡單(全局變量就能夠了),而多進程之間的通訊相對而言更繁瑣一些,呵呵...多線程

 

咱們的問題如何產生的?問題的根本緣由是什麼?

事情是這樣的,模塊之間須要通訊,咱們用了openwrt的開源代碼ubus作消息轉發socket

在咱們的每一個須要通訊的模塊中建立了一個線程(ubus thread)循環接收ubusd轉發而來的消息(用的是libubox提供的API  uloop_run)工具

在模塊須要發送時,主線程調用ubus的消息發送接口(ubus_send_event)oop

大多數狀況是這樣的:spa

1. 模塊(做爲一個後臺進程)啓動時裝載了libubox.so(注意,這個庫的載入時加入了一個全局變量 int epoll_fd)命令行

2. 隨即就建立線程ubus thread循環等待接收消息,ubus thread的動做大體以下:線程

    a. 創建和ubusd通訊的socket(記爲fd1)設計

    b. 隨即調用epoll_ctl將fd1加入到epoll_fd中繼承

    c. 而後調用epoll_wait....接口

3. 主線程執行,在有須要的時候,調用ubus_send_event發送

    實際上這個庫接口作的動做是這樣的:

    a. 創建和ubusd通訊的socket(記爲fd2)

    b. 將fd2加入到全局變量epoll_fd,而後執行epoll_wait(epoll_fd沒有建立的話,先調用epoll_create)

那麼問題來了,通常都是ubus thread先執行,而後阻塞在epoll_wait中,主線程在ubus thread阻塞時將fd2加入到同一個epoll_fd中....

也就是兩線程在操做同一個epoll_fd

結果fd2狀態發生變化時,ubus thread被喚醒執行了,而後就亂套了......

 

嘗試了一下,在主線程發送的時候去fork子進程,子進程完成發送的動做,反而更悲劇了,整個進程崩掉了....

爲啥呢,由於fork出來的子進程沒有執行exec切換進程執行上下文,徹底是一個父進程的拷貝,那個出問題的epoll_fd也被它拿着了

而後子進程新建了一個和ubusd通訊的fd2,加入到這個epoll_fd中,而後執行epoll_wait

結果fd2發生狀態變化時,內核喚醒了ubus thread,尼瑪,ubus thread哪裏知道fd2的存在,結果非法地址訪問,Segmentfault....呵呵...


最後,最後,由於咱們這羣小蜜蜂實在是飛得過低,因此,咱們藉助了ubus源碼附帶提供的ubus命令行工具

在主線程發送時 system("ubus send %s ", message)

這就至關於在主線程發送時fork子進程,而後子進程的執行環境切換到ubus工具,ubus工具會調用ubus_send_event

 

另外一種解決方案:

仍是在主線程發送的時候去fork子進程,子進程一上來直接去循環關閉從0-1024的fd,哈哈哈哈...(不知道會不會有什麼其餘的影響,不過我以爲應該能夠)

for (i = 0; i < FDSET; i++)

  close(i)

這樣作是強迫子進程再次去調用epoll_create,而不是複用從父進程那裏繼承而來的epoll_fd。

 

因此,用了開源庫,加上咱們獨特的線程設計,給本身整了個大坑....

相關文章
相關標籤/搜索