比起多進程來講,線程間通訊簡單(全局變量就能夠了),而多進程之間的通訊相對而言更繁瑣一些,呵呵...多線程
事情是這樣的,模塊之間須要通訊,咱們用了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。
因此,用了開源庫,加上咱們獨特的線程設計,給本身整了個大坑....