第七色在线视频,2021少妇久久久久久久久久,亚洲欧洲精品成人久久av18,亚洲国产精品特色大片观看完整版,孙宇晨将参加特朗普的晚宴

為了賬號安全,請及時綁定郵箱和手機立即綁定
已解決430363個問題,去搜搜看,總會有你想問的

如何避免在信號處理程序中使用printf?

如何避免在信號處理程序中使用printf?

DIEA 2019-06-03 13:48:45
如何避免在信號處理程序中使用printf?自printf不是可重入的,在信號處理程序中使用它是不安全的。但我見過很多示例代碼printf這邊請。所以我的問題是:我們什么時候需要避免使用printf在信號處理程序中,是否建議替換?
查看完整描述

3 回答

?
慕桂英546537

TA貢獻1848條經(jīng)驗 獲得超10個贊

您可以使用一些標(biāo)志變量,在信號處理程序中設(shè)置該標(biāo)志,并基于該標(biāo)志調(diào)用。printf()在正常運行過程中,在main()或程序的其他部分中起作用。

調(diào)用所有函數(shù)并不安全,例如printf,在信號處理程序中。一種有用的技術(shù)是使用信號處理程序來設(shè)置flag然后檢查一下flag從主程序中打印一條消息,如果需要的話。

注意,在下面的示例中,信號處理程序ding()設(shè)置了一個標(biāo)志alarm_fired以1作為SIGALRM的捕獲和主要功能alarm_fired值進行檢查,以便有條件地正確調(diào)用printf。

static int alarm_fired = 0;void ding(int sig) // can be called asynchronously{
  alarm_fired = 1; // set flag}int main(){
    pid_t pid;
    printf("alarm application starting\n");
    pid = fork();
    switch(pid) {
        case -1:
            /* Failure */
            perror("fork failed");
            exit(1);
        case 0:
            /* child */
            sleep(5);
            kill(getppid(), SIGALRM);
            exit(0);
    }
    /* if we get here we are the parent process */
    printf("waiting for alarm to go off\n");
    (void) signal(SIGALRM, ding);
    pause();
    if (alarm_fired)  // check flag to call printf
      printf("Ding!\n");
    printf("done\n");
    exit(0);}

參考資料:開始Linux編程,第4版,在這本書中,您的代碼將被解釋(您想要什么),第11章:過程和信號,第484頁。

此外,在編寫處理程序函數(shù)時需要特別小心,因為它們可以異步調(diào)用。也就是說,處理程序可以在程序的任意點調(diào)用,這是不可預(yù)測的。如果兩個信號在很短的間隔內(nèi)到達,一個處理程序可以在另一個處理程序內(nèi)運行。人們認(rèn)為更好的做法是宣布volatile sigatomic_t,這種類型總是以原子方式訪問,避免了中斷對變量訪問的不確定性。(原文:原子數(shù)據(jù)存取和信號處理以獲得詳細(xì)的補償)。

朗讀,閱讀定義信號處理程序*學(xué)習(xí)如何編寫可以使用signal()sigaction()職能。
授權(quán)職能清單手冊頁,在信號處理程序中調(diào)用此函數(shù)是安全的。


查看完整回答
反對 回復(fù) 2019-06-03
?
繁星點點滴滴

TA貢獻1803條經(jīng)驗 獲得超3個贊


主要問題是如果信號中斷malloc()或者一些類似的函數(shù),內(nèi)部狀態(tài)可能暫時不一致,當(dāng)它在空閑列表和使用列表之間移動內(nèi)存塊時,或者其他類似的操作。如果信號處理程序中的代碼調(diào)用一個函數(shù),然后調(diào)用malloc(),這可能會完全破壞內(nèi)存管理。

對于在信號處理程序中可以做什么,C標(biāo)準(zhǔn)采取了非常保守的觀點:

ISO/IEC 9899:2011§7.14.1.1signal功能

5如果信號發(fā)生時不是由于調(diào)用abortraise函數(shù)時,如果信號處理程序引用任何具有靜態(tài)或線程存儲持續(xù)時間的對象,而該對象不是無鎖原子對象,則行為是未定義的,除非將值賦值給聲明為volatile sig_atomic_t,或者信號處理程序調(diào)用標(biāo)準(zhǔn)庫中的除abort函數(shù)_Exit函數(shù)quick_exit函數(shù),或signal函數(shù)的第一個參數(shù)等于與導(dǎo)致調(diào)用處理程序的信號對應(yīng)的信號。此外,如果對signal函數(shù)的結(jié)果是SIG_ERR返回值errno是不確定的。252)

252)如果任何信號是由異步信號處理程序生成的,則該行為是未定義的。

對于在信號處理程序中可以做什么,POSIX要慷慨得多。

信號概念在2008年P(guān)OSIX版中說:

如果進程是多線程的,或者進程是單線程的,并且執(zhí)行信號處理程序的結(jié)果是:

  • 進程調(diào)用abort()raise()kill()pthread_kill(),或sigqueue()若要生成未被阻塞的信號,請執(zhí)行以下操作

  • 正在解除阻塞并在解除阻塞的調(diào)用返回之前傳遞的掛起信號

如果信號處理程序引用除errno使用靜態(tài)存儲持續(xù)時間,而不是將值賦值給聲明為volatile sig_atomic_t,或者如果信號處理程序調(diào)用在此標(biāo)準(zhǔn)中定義的除下表所列函數(shù)之外的任何函數(shù)。

下表定義了一組應(yīng)該是異步信號安全的函數(shù).因此,應(yīng)用程序可以不受限制地從信號捕獲函數(shù)調(diào)用它們:

_Exit()             fexecve()           posix_trace_event() sigprocmask()_exit()             fork()              
pselect()           sigqueue()…fcntl()             pipe()              sigpause()          
write()fdatasync()         poll()              sigpending()

上表中沒有的所有功能都被認(rèn)為在信號方面是不安全的。在信號存在的情況下,本卷POSIX.1-2008所定義的所有函數(shù)在從信號捕捉函數(shù)調(diào)用或被信號捕獲函數(shù)中斷時都應(yīng)表現(xiàn)為定義的功能,但有一個例外:當(dāng)信號中斷不安全的函數(shù),而信號捕捉函數(shù)調(diào)用不安全的函數(shù)時,則行為未定義。

獲得以下值的操作:errno和將值賦值給errno應(yīng)該是異步信號安全的。

當(dāng)信號被傳遞到線程時,如果該信號的動作指定終止、停止或繼續(xù),則整個進程將分別終止、停止或繼續(xù)。

但是,printf()該列表中明顯沒有函數(shù)族,信號處理程序可能無法安全地調(diào)用這些函數(shù)。

這個2016年P(guān)OSIXUPDATE擴展了安全函數(shù)列表,特別包括了<string.h>,這是一個特別有價值的補充(或者說是一個特別令人沮喪的疏忽)。現(xiàn)在的清單是:

_Exit()              getppid()            sendmsg()            tcgetpgrp()

_exit()              getsockname()        sendto()             tcsendbreak()

abort()              getsockopt()         setgid()             tcsetattr()

accept()             getuid()             setpgid()            tcsetpgrp()

access()             htonl()              setsid()             time()

aio_error()          htons()              setsockopt()         timer_getoverrun()

aio_return()         kill()               setuid()             timer_gettime()

aio_suspend()        link()               shutdown()           timer_settime()

alarm()              linkat()             sigaction()          times()

bind()               listen()             sigaddset()          umask()

cfgetispeed()        longjmp()            sigdelset()          uname()

cfgetospeed()        lseek()              sigemptyset()        unlink()

cfsetispeed()        lstat()              sigfillset()         unlinkat()

cfsetospeed()        memccpy()            sigismember()        utime()

chdir()              memchr()             siglongjmp()         utimensat()

chmod()              memcmp()             signal()             utimes()

chown()              memcpy()             sigpause()           wait()

clock_gettime()      memmove()            sigpending()         waitpid()

close()              memset()             sigprocmask()        wcpcpy()

connect()            mkdir()              sigqueue()           wcpncpy()

creat()              mkdirat()            sigset()             wcscat()

dup()                mkfifo()             sigsuspend()         wcschr()

dup2()               mkfifoat()           sleep()              wcscmp()

execl()              mknod()              sockatmark()         wcscpy()

execle()             mknodat()            socket()             wcscspn()

execv()              ntohl()              socketpair()         wcslen()

execve()             ntohs()              stat()               wcsncat()

faccessat()          open()               stpcpy()             wcsncmp()

fchdir()             openat()             stpncpy()            wcsncpy()

fchmod()             pause()              strcat()             wcsnlen()

fchmodat()           pipe()               strchr()             wcspbrk()

fchown()             poll()               strcmp()             wcsrchr()

fchownat()           posix_trace_event()  strcpy()             wcsspn()

fcntl()              pselect()            strcspn()            wcsstr()

fdatasync()          pthread_kill()       strlen()             wcstok()

fexecve()            pthread_self()       strncat()            wmemchr()

ffs()                pthread_sigmask()    strncmp()            wmemcmp()

fork()               raise()              strncpy()            wmemcpy()

fstat()              read()               strnlen()            wmemmove()

fstatat()            readlink()           strpbrk()            wmemset()

fsync()              readlinkat()         strrchr()            write()

ftruncate()          recv()               strspn()

futimens()           recvfrom()           strstr()

getegid()            recvmsg()            strtok_r()

geteuid()            rename()             symlink()

getgid()             renameat()           symlinkat()

getgroups()          rmdir()              tcdrain()

getpeername()        select()             tcflow()

getpgrp()            sem_post()           tcflush()

getpid()             send()               tcgetattr()

因此,您要么使用write()所提供的格式設(shè)置支持。printf()等,否則您將設(shè)置一個標(biāo)志,在代碼中的適當(dāng)位置(定期)進行測試。此技術(shù)在回答通過格里杰什·肖漢.


標(biāo)準(zhǔn)C功能和信號安全

克雷 一個有趣的問題,我只有一個部分的答案:

為什么大多數(shù)字符串函數(shù)都是從<string.h>的字符類函數(shù)。<ctype.h>還有更多的C標(biāo)準(zhǔn)庫函數(shù)不在上面的列表中嗎?實現(xiàn)需要有目的邪惡才能實現(xiàn)。strlen()從信號處理程序調(diào)用不安全。

中的許多函數(shù)<string.h>,很難理解為什么它們沒有被宣布為異步信號安全,我同意strlen()是一個很好的例子,以及strchr()strstr()等另一方面,其他功能,如strtok()strcoll()strxfrm()是相當(dāng)復(fù)雜的,不太可能是異步信號安全的。因為strtok()保留調(diào)用之間的狀態(tài),信號處理程序無法很容易地判斷正在使用的代碼的某些部分。strtok()都會搞砸的。這個strcoll()strxfrm()函數(shù)處理對地區(qū)敏感的數(shù)據(jù),加載區(qū)域設(shè)置涉及各種狀態(tài)設(shè)置.

的函數(shù)(宏)<ctype.h>都是區(qū)域敏感的,因此可能遇到與strcoll()strxfrm().

我很難理解為什么<math.h>是不安全的異步信號,除非是因為它們可能會受到SIGFPE(浮點異常)的影響,盡管這幾天我只看到一次。整型除以零。類似的不確定性產(chǎn)生于<complex.h><fenv.h><tgmath.h>.

中的一些功能<stdlib.h>可以被豁免-abs()例如。另一些具體問題是:malloc()家庭就是最好的例子。

可以對POSIX環(huán)境中使用的標(biāo)準(zhǔn)C(2011)中的其他標(biāo)頭進行類似的評估。(標(biāo)準(zhǔn)C是如此嚴(yán)格,在純標(biāo)準(zhǔn)C環(huán)境中分析它們是沒有興趣的。)那些標(biāo)記為“區(qū)域相關(guān)的”是不安全的,因為操作區(qū)域設(shè)置可能需要內(nèi)存分配,等等。

  • <assert.h> — 可能不安全

  • <complex.h> — 可能安全

  • <ctype.h>

    -不安全
  • <errno.h>

    -安全
  • <fenv.h> — 可能不安全

  • <float.h>

    -沒有職能
  • <inttypes.h>

    -區(qū)域敏感功能(不安全)
  • <iso646.h>

    -沒有職能
  • <limits.h>

    -沒有職能
  • <locale.h>

    -區(qū)域敏感功能(不安全)
  • <math.h> — 可能安全

  • <setjmp.h>

    -不安全
  • <signal.h>

    -允許
  • <stdalign.h>

    -沒有職能
  • <stdarg.h>

    -沒有職能
  • <stdatomic.h> — 可能安全,可能不安全

  • <stdbool.h>

    -沒有職能
  • <stddef.h>

    -沒有職能
  • <stdint.h>

    -沒有職能
  • <stdio.h>

    -不安全
  • <stdlib.h>

    -并非所有的安全(有些是允許的;另一些是不允許的)
  • <stdnoreturn.h>

    -沒有職能
  • <string.h>

    -并非所有的安全
  • <tgmath.h> — 可能安全

  • <threads.h> — 可能不安全

  • <time.h>

    -地點依賴性(但

    time()

    顯式允許)
  • <uchar.h>

    -地點依賴性
  • <wchar.h>

    -地點依賴性
  • <wctype.h>

    -地點依賴性

分析POSIXHeader將是…更困難的是,它們很多,有些函數(shù)可能是安全的,但許多不是…但也更簡單,因為POSIX說哪些函數(shù)是異步信號安全的(不是很多)。請注意,如下所示的標(biāo)題<pthread.h>有三個安全功能和許多不安全功能。

注:在POSIX環(huán)境中,幾乎所有對C函數(shù)和頭的評估都是半信半疑的猜測。這是沒有意義的,一個標(biāo)準(zhǔn)機構(gòu)的明確聲明。


查看完整回答
反對 回復(fù) 2019-06-03
?
子衿沉夜

TA貢獻1828條經(jīng)驗 獲得超3個贊

如何避免使用printf在信號處理器里?

  1. 總是避開它,會說:只是不要用printf()在信號處理程序中。

  2. 至少在POSIX一致性系統(tǒng)上,您可以使用write(STDOUT_FILENO, ...)而不是printf()..然而,格式化可能并不容易:使用寫或異步安全函數(shù)從信號處理程序打印int


查看完整回答
反對 回復(fù) 2019-06-03
  • 3 回答
  • 0 關(guān)注
  • 1330 瀏覽
慕課專欄
更多

添加回答

舉報

0/150
提交
取消
微信客服

購課補貼
聯(lián)系客服咨詢優(yōu)惠詳情

幫助反饋 APP下載

慕課網(wǎng)APP
您的移動學(xué)習(xí)伙伴

公眾號

掃描二維碼
關(guān)注慕課網(wǎng)微信公眾號