亚洲av成人无遮挡网站在线观看,少妇性bbb搡bbb爽爽爽,亚洲av日韩精品久久久久久,兔费看少妇性l交大片免费,无码少妇一区二区三区

  免費注冊 查看新帖 |

Chinaunix

  平臺 論壇 博客 文庫
最近訪問板塊 發(fā)新帖
查看: 3530 | 回復: 3
打印 上一主題 下一主題

【分享】優(yōu)雅處理段錯誤 [復制鏈接]

論壇徽章:
0
跳轉到指定樓層
1 [收藏(0)] [報告]
發(fā)表于 2012-04-20 20:21 |只看該作者 |倒序瀏覽
本帖最后由 wwdwwd 于 2012-04-20 20:23 編輯

摘要:某些進程在結束前必須要處理一些額外的過程才能結束,尤其是數(shù)據(jù)存儲的模塊,進程停止前為保證數(shù)據(jù)的完整性可能要做一些事情,如果發(fā)生段錯誤,這時就需要先截獲segv信號,處理完后再讓程序出core
一般進程收到段錯誤信號默認是dump core文件然后退出,但有些進程在退出時需要處理額外的過程才能結束,這時就不能讓信號執(zhí)行默認的動作了,我們就需要截獲段錯誤信號,然后在信號處理函數(shù)中
處理額外過程,我們稱之為other_function,但是我們處理完后其實還是需要讓程序core出來,以便知道是哪兒出問題了。
基礎知識預備:
1.對線程而言,有三種信號類型:異步信號,同步信號,定向信號。其中異步信號是指傳遞給某些解除了對該信號的阻塞的線程的信號,同步信號是指傳遞給引發(fā)該信號的線程的信號,定向信號是指由pthread_kill函數(shù)發(fā)送給指定線程的信號。像SIGSEGV(段錯誤信號),SIGPFE(浮點錯誤)這樣的錯誤信號就是同步于引發(fā)他們的線程的,因為引發(fā)這些信號的線程將等待信號處理程序處理完成后才能繼續(xù)進行,這樣的信號只能由本線程處理,而其他信號因為不與特定的線程相關,所以他們是異步的,例如其他進程給本進程發(fā)送的信號。如果有幾個線程都解除了對同一個異步信號的阻塞,當有信號到達時,線程運行系統(tǒng)就從中選取一個來處理。
2.對于SIGSEGV信號,如果是由進程段錯誤導致的,則只能設定信號處理函數(shù),不能阻塞或忽略,如果有是由別的進程發(fā)送的,則可以阻塞或忽略。
我們考慮了大概三個方案:
方案1:直接設置信號處理函數(shù),在信號處理函數(shù)中處理other_function,處理完后再signal(SIGSEGV,SIG_DFL),這看起來比較完美,但實際上有鎖的問題。如果出現(xiàn)段錯誤的線程中使用了鎖,在沒有解鎖之前發(fā)生段錯誤,other_function中也使用了同一個鎖,則容易出現(xiàn)死鎖,造成進程hang住。other_function中無鎖時此方案比較簡單易行。
方案2:其他線程阻塞信號,由專有線程處理段錯誤信號。這個不可行,因為我們之前說了,段錯誤信號如果由進程產生則不能被阻塞或忽略
方案3:直接設置信號處理函數(shù),但使用專有線程處理other_function。接到段錯誤信號后調用信號處理函數(shù),信號處理函數(shù)中設置開始處理標記,然后定期檢查專有線程是否處理完,專有線程定期檢查開始處理標記,發(fā)現(xiàn)設定了就開始處理other_function,處理完之后設置處理完標記,然后推出。信號處理函數(shù)中定期檢查處理完標記,發(fā)現(xiàn)一旦被處理完了則再signal(SIGSEGV,SIG_DFL),然后退出,等待出core。
這個方案也會出現(xiàn)方案1中的死鎖問題,但是此時的死鎖是兩個線程之間的死鎖,而不是同一個線程的死鎖,所以是可以處理的,信號處理函數(shù)中設置一個超時時間即可,即信號處理函數(shù)發(fā)現(xiàn)專有線程太久沒有處理完other_function就知道出現(xiàn)死鎖了,這時沒轍了,直接signal(SIGSEGV,SIG_DFL),讓程序出core完事,由于這種可能是比較少的,所以是可以接受的。
另外一個問題是:如果other_function中本身也出core就比較囧了,此時可以在信號處理函數(shù)中做判斷,如果開始處理標記已設定,說明已經已經在處理core了,再進來就直接signal(SIGSEGV,SIG_DFL),讓程序出core了事
說的比較亂,直接看代碼吧
  1. #include <stdint.h>
  2. #include <stdio.h>
  3. #include <pthread.h>
  4. #include <stdlib.h>
  5. #include <unistd.h>
  6. #include <signal.h>
  7. #include <string.h>
  8. volatile bool begin_segv_handle=false;
  9. volatile bool already_handle_other_function=false;
  10. void segv_handler(int signo);

  11. void * core_thread(void *args) {
  12.         int i=0;
  13.         while(1) {
  14.                 printf("in core thread\n");
  15.                 sleep(1);
  16.                 if(i++>2) {
  17.                         strcpy(NULL,"abc");
  18.                 }
  19.         }
  20.         return NULL;
  21. }

  22. void * other_function_thread(void *args) {
  23.         int i=0;
  24.         while(1) {
  25.                 printf("in other_function_thread\n");
  26.                 if(begin_segv_handle) {
  27.                         printf("set already_handle_other_function\n");
  28.                         already_handle_other_function = true;
  29.                         break;
  30.                 }
  31.                 sleep(1);
  32.         }
  33.         return NULL;
  34. }
  35. void segv_handler(int signo) {
  36.         printf("in segv_handler\n");
  37.         if(begin_segv_handle) {
  38.                 signal(SIGSEGV,SIG_DFL);
  39.                 return ;
  40.         }
  41.         begin_segv_handle = true;
  42.         int i=0;
  43.         while(1) {
  44.                 if(i++>10) {
  45.                         break;
  46.                 }
  47.                 if(already_handle_other_function){
  48.                         break;               
  49.                 }
  50.                 sleep(1);
  51.                
  52.         }
  53.         signal(SIGSEGV,SIG_DFL);
  54. }
  55. int main(void)
  56. {
  57.         signal(SIGSEGV,segv_handler);
  58.         pthread_t tid_core_thread=0UL,tid_other_function_thread=0UL;
  59.         pthread_create(&tid_core_thread,NULL,core_thread,NULL);
  60.         pthread_create(&tid_other_function_thread,NULL,other_function_thread,NULL);
  61.         pthread_join(tid_core_thread,NULL);
  62.         pthread_join(tid_other_function_thread,NULL);
  63.         return 0;
  64. }
復制代碼

論壇徽章:
0
2 [報告]
發(fā)表于 2012-04-20 21:11 |只看該作者
說的不錯,受益匪淺,謝謝指導

論壇徽章:
0
3 [報告]
發(fā)表于 2012-04-21 00:52 |只看該作者
一旦發(fā)生段錯誤,內存中的數(shù)據(jù)應全部被認為不可信任。
任何依靠段錯誤之前的內存中不可信任數(shù)據(jù)的處理,實際上都可能是擴散故障。程序已經段錯誤了,你再“保持數(shù)據(jù)完整性”是完全沒意義的。
簡單core dump后異常終止是最明智的處理。

論壇徽章:
0
4 [報告]
發(fā)表于 2012-04-22 14:19 |只看該作者
JohnBull 發(fā)表于 2012-04-21 00:52
一旦發(fā)生段錯誤,內存中的數(shù)據(jù)應全部被認為不可信任。
任何依靠段錯誤之前的內存中不可信任數(shù)據(jù)的處理,實 ...

1.段錯誤不等同于內存覆蓋,內存中的數(shù)據(jù)不是完全不可信任;
2.在多人協(xié)作的模塊,別人的程序發(fā)生段錯誤,一般不會損壞我的數(shù)據(jù),因為我的數(shù)據(jù)一般是單獨的線程,暴露有限的接口,不會讓外人直接訪問我的數(shù)據(jù);
3.如果發(fā)生內存覆蓋這樣的錯誤,只要不是特別嚴重的,一般數(shù)據(jù)都不會被損壞。因為別的線程覆蓋棧中的數(shù)據(jù)跟我沒關系,覆蓋堆中的數(shù)據(jù),只有不涉及到我的線程,問題也不大,因為每個線程的使用的堆地址空間是隔開的。
4.有一些數(shù)據(jù)模塊是這樣的:停止進程前dump數(shù)據(jù)索引,啟動時根據(jù)索引啟動會很快,如果沒有索引就巨慢,一般需要啟動1個小時以上,如果真的是出core后不dump索引的話,就會面臨著模塊1小時無法服務的困境,是非常危險的。
您需要登錄后才可以回帖 登錄 | 注冊

本版積分規(guī)則 發(fā)表回復

  

北京盛拓優(yōu)訊信息技術有限公司. 版權所有 京ICP備16024965號-6 北京市公安局海淀分局網監(jiān)中心備案編號:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年舉報專區(qū)
中國互聯(lián)網協(xié)會會員  聯(lián)系我們:huangweiwei@itpub.net
感謝所有關心和支持過ChinaUnix的朋友們 轉載本站內容請注明原作者名及出處

清除 Cookies - ChinaUnix - Archiver - WAP - TOP