0

コードを実装しているので、ネットワーク接続が到着したら受け入れ、到着ソケットから切り離し、std::packaged_task タスクを作成し、そのタスクを deque コンテナーにキューに入れ、後でそれらのタスクをタスク スレッドで実行します。Bo Qian の YouTube レクチャー「C++ Threading #9: packaged_task」では、これを簡単に行う方法が説明されています。

#include "stdafx.h"
#include <afxsock.h>
#include <condition_variable>
#include <deque>
#include <future>

std::condition_variable notifyDequeNotEmptyCondVar;
std::mutex decodeMu;

class MyRxDecode : public CAsyncSocket
{
public:
  static std::deque< std::packaged_task< bool() > > rxAcceptedTasks;

  static bool StartDecode( SOCKET socket )
  {
    bool result = true;

    // Attach detached socket to this socket
    //result = Attach( socket ); //  error C2352: 'CAsyncSocket::Attach': illegal call of non-static member function
    return result;
  }

  static bool DecodeTaskThread()
  {
    std::packaged_task< bool() > DecodingTask;

    {
      std::unique_lock< std::mutex > dequeLocker( decodeMu ); // makes sure all deque actions are atomic
      notifyDequeNotEmptyCondVar.wait( dequeLocker, [] () { return !rxAcceptedTasks.empty(); } ); // wait until notified that deque is not empty
      DecodingTask = std::move( rxAcceptedTasks.front() );
      rxAcceptedTasks.pop_front();
    }

    DecodingTask(); // has no arg because the arg was previously bound to the functor passed in

    return true;
  }
};


class MyListener : CAsyncSocket
{
  virtual void OnAccept( int nErrorCode ) // is called when other socket does a connect on this socket's endpoint
  {
    CAsyncSocket syncSocket; // msdn prescribes creating stack socket
    if( Accept( syncSocket ) )
    {
      AsyncSelect( FD_READ | FD_CLOSE ); // msdn
      SOCKET socket = syncSocket.Detach(); // msdn

      // Bo Qian's lecture explains how this packaged task code works and is made thread safe.
      // Create task in separate thread to process this connection and push onto deque. The main advantage of a packaged task compared to using a functor is the former links the callable object to a future, which is useful in a multi-threaded environment (Bo Qian).
      std::thread decodeThread( MyRxDecode::DecodeTaskThread ); // pass-by-value ctor
      std::packaged_task< bool() > rxAcceptTask( std::bind( MyRxDecode::StartDecode, socket ) ); // binds function with its param to create functor wh is passed to packaged task's ctor
      std::future< bool > rxAcceptTaskFuture = rxAcceptTask.get_future();

      {
        std::lock_guard< std::mutex > locker( decodeMu );
        MyRxDecode::rxAcceptedTasks.push_back( std::move( rxAcceptTask ) );
      }
      notifyDequeNotEmptyCondVar.notify_one();
      bool taskResult = rxAcceptTaskFuture.get();
      decodeThread.join();

      CAsyncSocket::OnAccept( nErrorCode ); // msdn
    }
  }
};

std::deque< std::packaged_task< bool() > > MyRxDecode::rxAcceptedTasks;

int main()
{
  return 0;
}

私の StartDecode は非静的 Attach を呼び出そうとする静的メソッドであるため、私の場合、コードはコンパイルされません。std::bind を使用して「ソケット」をタスクにバインドするため、StartDecode は静的メソッドです。'socket' は通常 StartDecode メソッドに渡されますが、パッケージ化されたタスクの 'future' が適切に機能するためには、渡されたパラメーターを std::bind を使用して事前にバインドする必要があります。ただし、StartDecode が静的になると、静的ではない CAsyncSocket の Attach を呼び出すと、エラー C2352 が発生します。

静的 MyRxDecode::StartDecode から非静的 Attach メソッドを呼び出すにはどうすればよいですか? ソケットパラメーターを静的にせずにタスクにバインドする必要を回避する方法はありますか?

4

1 に答える 1

0

std::bind を使用すると、非静的メンバー関数を呼び出すことができます。cppreference.com->std::bind を参照してください:

Notes
… when invoking a pointer to non-static member function or pointer to  
non-static data member, the first argument has to be a reference or pointer (including, 
possibly, smart pointer such as std::shared_ptr and std::unique_ptr) to an object whose 
member will be accessed. 

上記のコードのrxAcceptTaskの定義を次のように置き換えます。

std::packaged_task< bool() > rxAcceptTask( std::bind( &MyRxDecode::StartDecode, &myRxDecode, socket ) );

bool StartDecode ( SOCKET socket )メンバー関数を非静的にします。

于 2016-06-14T21:05:33.957 に答える