GTK+ 馬戲團:邪惡的 g_signal_connect 出場
GTK+ 馬戲團有五花八門的精彩表演,而今天壓軸好戲就是『邪惡的野獸 - g_signal_connect 』。g_signal_connect 可以戰勝所有的 widget 和 window,有強而有力的爪子,能劃破層層阻礙;有尖銳嚇人的牙齒,只須咬一口便深可見骨。雖然它已被馴服,但隨時還是有機會獸性大發反撲過來。:P
GTK+ Program 本身並不難,就算是第一次接觸的人,也能輕易上手並寫出什麼東西來。但對於較常接觸 GTK+ programing 的人,卻常會抱怨 GTK+ 的設計,層層的 window 和 widget 常搞到什麼事都要兜個大圈才能解決。而對 GTK+ 設計架構和細節了解不夠透徹的人,更是常常寫 5 分鐘 code ,卻要花 5 個小時 debug ,小弟我就是最好的例子 :(
所以,探討 GTK+ 的一些細節,有助於我們在撰寫 GTK+ 程式時避免問題的發生,減少 debug 的時間。
接觸過的人都曉得, GTK+ 的優點就是將各種東西都寫成一個個直接的 function call,任何人都可以很容易的去呼叫使用。但那些 function call 的背後常常各自為政互相打架,卡來卡去的結果不是『無限迴圈』就是『程式流程大亂』,我們如果不深入了解 GTK+ 的運作,這些問題將都會無解。
在 GTK+ 之中很多問題的發生,都是從邪惡的 g_signal_connect 開始。它是 GTK+ 各種物件的共通管道,programer 們可以利用它設定各種狀況的 handler,像是 widget 的 button-press-event, toggled ...etc。不過 g_signal_connect 所決定好的事,卻是有各種不同的觸發時機,有些會馬上就觸發如: toggled 事件,有些會在所有 event 處理完後,idle 時才觸發。若是沒有掌握好觸發的時機,一切的流程設計將會毀滅,而且找不到問題所在。
但是這些不同的時機,要深入了解 GTK+ Source 之後才會發現。對於一般 programer 來說,可沒這麼多時間一一深入了解每一個元件的運作,最好的解決辦法就是養成習慣,所有 widget 和 window 都設定好 Ready 之後,再呼叫 g_signal_connect 設定 event handler,這樣可以避免掉很多問題發生。
當然還有其他 g_signal_connect 衍生的問題,不過不再多提,有機會再整理成文好了。 :P
GTK+ Program 本身並不難,就算是第一次接觸的人,也能輕易上手並寫出什麼東西來。但對於較常接觸 GTK+ programing 的人,卻常會抱怨 GTK+ 的設計,層層的 window 和 widget 常搞到什麼事都要兜個大圈才能解決。而對 GTK+ 設計架構和細節了解不夠透徹的人,更是常常寫 5 分鐘 code ,卻要花 5 個小時 debug ,小弟我就是最好的例子 :(
所以,探討 GTK+ 的一些細節,有助於我們在撰寫 GTK+ 程式時避免問題的發生,減少 debug 的時間。
接觸過的人都曉得, GTK+ 的優點就是將各種東西都寫成一個個直接的 function call,任何人都可以很容易的去呼叫使用。但那些 function call 的背後常常各自為政互相打架,卡來卡去的結果不是『無限迴圈』就是『程式流程大亂』,我們如果不深入了解 GTK+ 的運作,這些問題將都會無解。
在 GTK+ 之中很多問題的發生,都是從邪惡的 g_signal_connect 開始。它是 GTK+ 各種物件的共通管道,programer 們可以利用它設定各種狀況的 handler,像是 widget 的 button-press-event, toggled ...etc。不過 g_signal_connect 所決定好的事,卻是有各種不同的觸發時機,有些會馬上就觸發如: toggled 事件,有些會在所有 event 處理完後,idle 時才觸發。若是沒有掌握好觸發的時機,一切的流程設計將會毀滅,而且找不到問題所在。
但是這些不同的時機,要深入了解 GTK+ Source 之後才會發現。對於一般 programer 來說,可沒這麼多時間一一深入了解每一個元件的運作,最好的解決辦法就是養成習慣,所有 widget 和 window 都設定好 Ready 之後,再呼叫 g_signal_connect 設定 event handler,這樣可以避免掉很多問題發生。
當然還有其他 g_signal_connect 衍生的問題,不過不再多提,有機會再整理成文好了。 :P
其實重點就是....
回覆刪除你 call 的每個 API 內部,都可能觸動該物件定義的事件
如果在那個 API 操作了物件後,引發了一個事件,
在你的 function call 還沒返回之前,
這個事件,就會先沿著整個訊息的傳遞鍊,
一個個傳遞到所有連接到這個 signal 的
handler,直到所有 handler 都呼叫完,
或是中途有人要求停止,打斷了這個傳遞
你的 function call 才會返回。
所以...當你在一個 signal handler 內,
對自身物件呼叫其他 API 時,你要小心
這個操作,可能會引起某些你沒想到的事件
而這個事件,很可能會呼叫到你現在所在的handler。
於是,在你的 function call 返回之前,
你自己這個 handler 本身,又被呼叫了一次,
就形成了遞迴,而被呼叫的 handler 裡面,
又不小心觸動了同一個事件,導致自己本身
的 handler 又被呼叫一次,變成無窮遞迴,
最後的下場,當然就是 stack overflow。
這只是眾多 gtk+ 陷阱之一而已 XD