到着時にネットワーク接続を受け入れ、到着ソケットからネットワーク接続を切り離し、std :: packaged_taskタスクを作成し、そのタスクをdequeコンテナーにキューに入れ、後でタスクスレッドでそれらのタスクを実行できるようにコードを実装しています。これを簡単にするのは、これを行う方法を示す「C ++スレッド#9:packaged_task」に関するBoQianのYouTube講義です。
#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メソッドを呼び出すにはどうすればよいですか?ソケットパラメータを静的にすることなくタスクにバインドする必要を回避する方法はありますか?
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 ) );
することができますブールStartDecodeを(SOCKETソケット)メンバ関数は非静的になります。
この記事はインターネットから収集されたものであり、転載の際にはソースを示してください。
侵害の場合は、連絡してください[email protected]
コメントを追加