Je vous implémentez du code que je peux accepter les connexions réseau à leur arrivée, les détacher de leur prise d'arrivée, Créez une tâche std :: packaged_task, mettez en file d'attente cette tâche dans un conteneur deque, puis exécutez ces tâches dans leur tâche plus tard. La conférence YouTube de Bo Qian sur "C++ Threading # 9: packaged_task" qui montre comment faire cela est facile.En utilisant std :: packaged_task à la file d'attente des tâches CAsyncSocket-Détacher-socket les causes compilent erreur en cas de non-statique Fixer est appelée à partir de la méthode statique
#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;
}
Le code ne compile pas dans mon cas parce que mon StartDecode est une méthode statique essayant d'appeler un non-statique Fixer. StartDecode est une méthode statique, car std :: bind est utilisé pour lier 'socket' à la tâche. 'Socket' devrait normalement être passé à la méthode StartDecode, mais pour que 'future' dans la tâche empaquetée fonctionne correctement, tous les paramètres passés doivent être liés à l'avance en utilisant std :: bind. Mais une fois que StartDecode est rendu statique, un appel à Attach de CAsyncSocket, qui est non statique, provoque l'erreur C2352.
Comment puis-je appeler la non-statique méthode Attach de MyRxDecode statique :: StartDecode? Y at-il un moyen d'éviter d'avoir à lier le paramètre socket à la tâche sans le rendre statique? Std :: bind permet d'appeler des fonctions membres non statiques.