1

O_NONBLOCKモードで名前付きパイプを作成し、別のスレッドで「SELECT」メソッドを使用して読み取りイベントをリッスンしようとしています。メインスレッドでスリープ時間を設定した後、プログラムを閉じようとすると問題が発生します。名前付きパイプのファイル記述子がcloseメソッドを使用して閉じられると、select操作はすぐに停止し、何らかの値を返すはずです。しかし、残念ながら、ファイル記述子が閉じられ、selectメソッドを実行するスレッドがハングした場合、select操作は反応しません...

それを解決する方法はありますか?サンプルコードは以下のとおりです。

#include <pthread.h>
#include <limits.h>
#include <cctype>
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <semaphore.h>
#include <sys/shm.h>
#include <sys/time.h>
#include <sys/timeb.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <exception>
#define BUFFER PIPE_BUF
#define LPVOID void *
#define BOOL int
#define TRUE 1
#define CONST const
#define CHAR char

class CPipeTest
{
    public:

    int fd;
    int nfd;
    fd_set rfd;
    pthread_t t;

    CPipeTest() {};
    ~CPipeTest() {};

    static LPVOID fnExecuteThread(LPVOID lpParam)
    {
        ((CPipeTest*)lpParam)->fnRunThread();
        return NULL;
    }

    BOOL fnRunThread()
    {
        printf("Going to listen...\r\n");
        select(nfd, &rfd, NULL, NULL, NULL);
        printf("Close listener...\r\n");
        return TRUE;
    }

    void fnInit()
    {
        CONST CHAR * name = "./test_fifo1";
        mkfifo(name, 0777);
        fd = open(name, O_NONBLOCK | O_RDONLY);
        nfd = fd + 1;
        FD_ZERO(&rfd);
        FD_SET(fd, &rfd);

        pthread_create( &t, NULL, fnExecuteThread, (LPVOID)this);

        sleep(30);
        printf("Close file descriptor - listener should be closed automatically and immediately\r\n");
        close(fd);
        printf("Descriptor closed wait for thread to to be closed\r\n");
        pthread_join(t, NULL);
        printf("Thread is closed - everything is fine\r\n");
    }

};

int main()
{
    CPipeTest pi;
    pi.fnInit();

    return 0;

}
4

3 に答える 3

0

あるスレッドで変数に書き込んだり、別のスレッドで変数から読み取ったりすることは避けてください。

そして避けることによって、私はそれをしないことを意味します。:)

使用するすべての変数は、fnRunThreadアクセスを同期していない限り、その関数によってのみ変更される必要があります。

ここに、あなたがしたことをしている人がい ます。別のスレッドでファイル記述子を閉じる(2)場合、select(2)は何をしますか? そして未定義の振る舞いが指摘されています。

これを修正する良い方法の1つは、FIFOに渡すことができる「読み取り停止」コマンドを用意することです。読み取りスレッドがそれを取得すると、読み取りを停止し、ファイルを閉じます。(読み取りスレッドはファイルハンドルを閉じることに注意してください。読み取りスレッドがファイルハンドルから読み取りを行っている場合、それはファイルハンドルを所有していることを意味します。追加の同期を除いて、スレッドを起動したら、次の変数からの読み取りまたは変数への書き込みのみを行う必要があります。スレッド内のスレッドによって所有されており、スレッドの外部でこれらの変数の読み取りまたは書き込みを行うことはできません)。

于 2013-01-14T21:55:06.997 に答える
0

2つのファイル記述子が必要です。1つは読み取り用、もう1つは書き込み用です。

ブロッキングモードの場合、書き込み用のもの(最初のスレッドで閉じます)は、「リーダー」スレッドを開始した後、最初のスレッドで開く必要があります。読み取り用のものは、リーダースレッドで開く必要があります。非ブロッキングモードの場合、最初に読み取り用に開いてから書き込み用に開くと、同じスレッドで実行できます(またはENXIO、リーダーなしでライターを開くために返されます)。

書き込み側を閉じると、読み取り側に。の通知が届きselectます。(実際のデータ交換がある場合、以下readはゼロバイトを読み取ります。これがEOFを検出する方法です)。

匿名パイプに切り替えると、pipe呼び出しから記述子のペアを自動的に取得します。

于 2013-01-14T21:58:49.887 に答える
0

問題は、FIFO(特殊なタイプのファイル)を使用する前に、FIFO(特殊なタイプのファイル)を両端で開く必要があることです。同じ端を閉じて、他のスレッドが反応することを期待するのは意味がありません。

次のコードはあなたが望むことをするはずです:

    ....
    nfd = fd + 1;
    FD_ZERO(&rfd);
    FD_SET(fd, &rfd);

    int write_fd = open(name, O_WRONLY);   // open the other end
    pthread_create( &t, NULL, fnExecuteThread, (LPVOID)this);

    sleep(30);
    printf("Close file descriptor - listener should be closed automatically and immediately\r\n");
    close(write_fd);                       // close the other end
    ....
于 2013-01-14T22:51:50.143 に答える