4

「man select」情報によると:

     "On  success,  select() and pselect() return the number of file descrip‐
   tors contained in the three returned  descriptor  sets which may be zero 
   if the timeout expires  before  anything  interesting happens.  On error, 
   -1 is returned, and errno is set appropriately; the sets and timeout become
   undefined, so do not  rely  on  their  contents after an error."

次の理由により、Select はウェイクアップします。

       1)read/write availability       
       2)select error                 
       3)descriptoris closed.  

しかし、利用可能なデータがなく、選択がまだタイムアウト内にある場合、どうすれば別のスレッドから select() を起こすことができますか?

[更新]
疑似コード

          // Thread blocks on Select
          void *SocketReadThread(void *param){
               ...
               while(!(ReadThread*)param->ExitThread()) {
                   struct timeval timeout;
                   timeout.tv_sec = 60; //one minute
                   timeout.tv_usec = 0;

                   fd_set rds;
                   FD_ZERO(&rds);
                   FD_SET(sockfd, &rds)'

                   //actually, the first parameter of select() is 
                    //ignored on windows, though on linux this parameter
                   //should be (maximum socket value + 1)
                   int ret = select(sockfd + 1, &rds, NULL, NULL, &timeout );
                   //handle the result
                   //might break from here

               }
               return NULL;
          }

          //main Thread
          int main(){
                //create the SocketReadThread
                ReaderThread* rthread = new ReaderThread;
                pthread_create(&pthreadid, NULL, SocketReaderThread, 
                          NULL, (void*)rthread);

                 // do lots of things here
                 ............................

                //now main thread wants to exit SocketReaderThread
                //it sets the internal state of ReadThread as true
                rthread->SetExitFlag(true);
                //but how to wake up select ??????????????????
                //if SocketReaderThread currently blocks on select
          }

[UPDATE]
1) @trojanfoe はこれを達成する方法を提供します。彼の方法はソケット データ (ダーティ データまたは終了メッセージ データの可能性があります) をウェイクアップ セレクトに書き込みます。テストを行い、そこで結果を更新します。
2)もう1つ言及することは、ソケットを閉じてもselect関数呼び出しが起動することを保証するものではありません。この投稿を参照してください。

[UPDATE2]多くのテストを行った後、select
ウェイクアップに関するいくつかの事実を以下に
示します。これ以降、ソケットからの読み取りまたはソケットへの書き込みは、errno = 0 で 0 の戻り値を取得します 2) select によって監視されているソケットが同じアプリケーションの別のスレッドによって閉じられている場合、select() は読み書きするデータはありません。select のタイムアウト後、読み取り/書き込み操作を行うと、errno = EBADF のエラーが発生します (タイムアウト期間中に別のスレッドによってソケットが閉じられたため)。

4

1 に答える 1

7

以下に基づいてイベントオブジェクトを使用しますpipe()

IoEvent.h:

#pragma once

class IoEvent {
protected:
    int m_pipe[2];
    bool m_ownsFDs;

public:
    IoEvent();              // Creates a user event
    IoEvent(int fd);        // Create a file event

    IoEvent(const IoEvent &other);

    virtual ~IoEvent();

    /**
     * Set the event to signalled state.
     */
    void set();

    /**
     * Reset the event from signalled state.
     */
    void reset();

    inline int fd() const {
        return m_pipe[0];
    }
};

IoEvent.cpp:

#include "IoEvent.h"
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <fcntl.h>
#include <poll.h>

using namespace std;

IoEvent::IoEvent() : 
    m_ownsFDs(true) {
    if (pipe(m_pipe) < 0)
        throw MyException("Failed to create pipe: %s (%d)", strerror(errno), errno);

    if (fcntl(m_pipe[0], F_SETFL, O_NONBLOCK) < 0)
        throw MyException("Failed to set pipe non-blocking mode: %s (%d)", strerror(errno), errno);
}

IoEvent::IoEvent(int fd) : 
    m_ownsFDs(false) {
    m_pipe[0] = fd;
    m_pipe[1] = -1;
}

IoEvent::IoEvent(const IoEvent &other) {
    m_pipe[0] = other.m_pipe[0];
    m_pipe[1] = other.m_pipe[1];
    m_ownsFDs = false;
}

IoEvent::~IoEvent() {
    if (m_pipe[0] >= 0) {
        if (m_ownsFDs)
            close(m_pipe[0]);

        m_pipe[0] = -1;
    }

    if (m_pipe[1] >= 0) {
        if (m_ownsFDs)
            close(m_pipe[1]);

        m_pipe[1] = -1;
    }
}

void IoEvent::set() {
    if (m_ownsFDs)
        write(m_pipe[1], "x", 1);
}

void IoEvent::reset() {
    if (m_ownsFDs) {
        uint8_t buf;

        while (read(m_pipe[0], &buf, 1) == 1)
            ;
    }
}

m_ownsFDsメンバーを捨てることができます。もうそれを使っているかどうかさえわかりません。

于 2013-07-02T13:07:05.923 に答える