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

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

如何檢查標準輸出是否已關(guān)閉 - 不向其寫入數(shù)據(jù)?

如何檢查標準輸出是否已關(guān)閉 - 不向其寫入數(shù)據(jù)?

Go
LEATH 2022-07-11 16:25:15
我編寫了一個程序,它讀取數(shù)據(jù)、過濾和處理數(shù)據(jù)并將其寫入標準輸出。如果標準輸出通過管道傳輸?shù)搅硪粋€進程,并且管道進程終止,我得到 SIGPIPEd,這很好,因為程序終止,并且管道及時結(jié)束。然而,根據(jù)過濾器參數(shù),可能有幾十秒沒有一次寫入,并且在此期間不會有 SIGPIPE,盡管下游進程早已完成。我怎樣才能檢測到這一點,而無需實際向標準輸出寫入內(nèi)容?目前,管道只是掛起,直到我的程序因自然原因終止。我試著寫一個零長度切片if _, err := os.Stdout.Write([]byte{}); err != nil但不幸的是,這不會導(dǎo)致錯誤。NB 理想情況下,無論平臺如何,這都應(yīng)該有效,但如果它僅適用于 Linux,那已經(jīng)是一種改進。
查看完整描述

2 回答

?
慕碼人2483693

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

這在 Go 中沒有回答,但你可能會找到一種使用它的方法。如果您可以將 Poll(2) 應(yīng)用于管道的寫入端,您將在它變得不可寫時收到通知。如何將其集成到您的 Go 代碼中取決于您的程序;希望它可能有用:


#include <errno.h>

#include <poll.h>

#include <signal.h>

#include <stdio.h>

#include <stdlib.h>

#include <string.h>

#include <unistd.h>


void sp(int sno) {

    write(2, "sigpipe!\n", 9);

    _exit(1);

}


int waitfd(int fd) {

    int n;

    struct pollfd p;

    p.fd = fd;

    p.events = POLLOUT | POLLRDBAND;

    /* RDBAND is for what looks like a bug in illumos fifovnops.c */

    p.revents = 0;

    if ((n=poll(&p, 1, -1)) == 1) {

        if (p.revents & POLLOUT) {

            return fd;

        }

        if (p.revents & (POLLERR|POLLHUP)) {

            return -1;

        }

    }

    fprintf(stderr, "poll=%d (%d:%s), r=%#x\n",

        n, errno, strerror(errno), p.revents);

    return -1;

}


int main() {

    int count = 0;

    char c;

    signal(SIGPIPE, sp);

    while (read(0, &c, 1) > 0) {

        int w;

        while ((w=waitfd(1)) != -1 &&

            write(1, &c, 1) != 1) {

        }

        if (w == -1) {

            break;

        }

        count++;

    }

    fprintf(stderr, "wrote %d\n", count);

    return 0;

}

在 linux 中,您可以將這個程序運行為:./a.out < /dev/zero | sleep 1,它會打印出類似的內(nèi)容:wrote 61441。您可以將其更改為休眠 3 秒,它會打印相同的內(nèi)容。這是一個很好的證據(jù),它已經(jīng)填滿了管道,正在等待空間。睡眠永遠不會從管道中讀取,因此當(dāng)它的時間到時,它會關(guān)閉讀取端,這會用 POLLERR 事件喚醒 poll(2)。


如果將輪詢事件更改為不包括 POLLOUT,您將獲得更簡單的程序:


#include <errno.h>

#include <fcntl.h>

#include <poll.h>

#include <signal.h>

#include <stdio.h>

#include <stdlib.h>

#include <string.h>

#include <unistd.h>


int waitfd(int fd) {

    int n;

    struct pollfd p;

    p.fd = fd;

    p.events = POLLRDBAND;

    p.revents = 0;

    if ((n=poll(&p, 1, -1)) == 1) {

        if (p.revents & (POLLERR|POLLHUP)) {

            return -1;

        }

    }

    fprintf(stderr, "poll=%d (%d:%s), r=%#x\n",

        n, errno, strerror(errno), p.revents);

    return -1;

}


int main() {

    if (waitfd(1) == -1) {

        fprintf(stderr, "Got an error!\n");

    }

    return 0;

}

“出錯了!” 表示管道已關(guān)閉。我不知道這是多么可移植,因為 poll(2) 文檔有點粗略。如果沒有 POLLRDBAND(所以 events 為 0),這適用于 Linux,但不適用于 UNIX(至少 Solaris 和 macos)。再一次,文檔沒用,但是內(nèi)核源代碼回答了很多問題:)


這個例子,使用線程,可以直接映射到go:


#include <pthread.h>

#include <errno.h>

#include <poll.h>

#include <signal.h>

#include <stdio.h>

#include <stdint.h>

#include <stdlib.h>

#include <string.h>

#include <unistd.h>


int Events = POLLRDBAND;


void sp(int sno) {

    char buf[64];

    write(2, buf, snprintf(buf, sizeof buf, "%d: sig%s(%d)\n", getpid(), sys_siglist[sno], sno));

    _exit(1);

}


int waitfd(int fd) {

    int n;

    struct pollfd p;

    p.fd = fd;

    p.events = Events;

    /* RDBAND is for what looks like a bug in illumos fifovnops.c */

    p.revents = 0;

    if ((n=poll(&p, 1, -1)) == 1) {

        if (p.revents & (POLLERR|POLLHUP)) {

            return -1;

        }

        return fd;

    }

    return -1;

}


void *waitpipe(void *t) {

    int x = (int)(intptr_t)t; /*gcc braindead*/

    waitfd(x);

    kill(getpid(), SIGUSR1);

    return NULL;

}


int main(int ac) {

    pthread_t killer;

    int count = 0;

    char c;

    

    Events |= (ac > 1) ? POLLOUT : 0;


    signal(SIGPIPE, sp);

    signal(SIGUSR1, sp);


    pthread_create(&killer, 0, waitpipe, (int *)1);

    while (read(0, &c, 1) > 0) {

        write(1, &c, 1);

        count++;

    }

    fprintf(stderr, "wrote %d\n", count);

    return 0;

}

請注意,它會在 poll 上駐留一個線程,并生成一個 SIGUSR1。這是運行它:


mcloud:pipe $ ./spthr < /dev/zero | hexdump -n80

0000000 0000 0000 0000 0000 0000 0000 0000 0000

*

0000050

185965: sigUser defined signal 1(10)

mcloud:pipe $ ./spthr < /dev/zero | sleep 1

185969: sigUser defined signal 1(10)

mcloud:pipe $ ./spthr | sleep 1

185972: sigUser defined signal 1(10)

mcloud:pipe $ ./spthr < /dev/zero | hexdump -n800000

0000000 0000 0000 0000 0000 0000 0000 0000 0000

*

00c3500

185976: sigBroken pipe(13)

在第一個命令中,hexdump 在 80 字節(jié)后退出,輪詢基本上是在與 read+write 循環(huán)競爭,因此它可能生成了一個 sigpipe 或 sigusr1。


后兩個演示了 sleep 將導(dǎo)致 sigusr1 (輪詢返回異常事件),無論管道讀取器退出時管道的寫入端是否已滿。


第四,使用 hexdump 讀取大量數(shù)據(jù),遠遠超過管道容量,這更確定性地導(dǎo)致了 sigpipe。


您可以生成更準確地對其建模的測試程序,但關(guān)鍵是一旦管道關(guān)閉,程序就會收到通知;不必等到下一次寫入。


查看完整回答
反對 回復(fù) 2022-07-11
?
千巷貓影

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

這不是問題的真正解決方案 - 即,檢測管道中的進程是否在沒有寫入的情況下終止 - 但這是一個解決方法,在 Daniel Farrell 的評論中建議:(定義和)使用將被忽略的心跳信號下游。

由于此解決方法不透明,因此如果您不控制所涉及的所有進程,則可能無法實現(xiàn)。

這是一個使用 NUL 字節(jié)作為基于文本數(shù)據(jù)的心跳信號的示例:

my-cmd | head -1 | tr -d '\000' > file

my-cmd 將在不活動時發(fā)送 NUL 字節(jié)以獲得及時的 EPIPE / SIGPIPE。

請注意,tr一旦達到其目的,使用 就再次剝離心跳 - 否則它們最終會出現(xiàn)在file.


查看完整回答
反對 回復(fù) 2022-07-11
  • 2 回答
  • 0 關(guān)注
  • 139 瀏覽
慕課專欄
更多

添加回答

舉報

0/150
提交
取消
微信客服

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

幫助反饋 APP下載

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

公眾號

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