2016-06-14 2 views
0

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.

Répondre

0

Voir 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. 

Remplacement de la définition de rxAcceptTask dans le code ci-dessus avec les éléments suivants:

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

permet la bool StartDecode (prise CREUSE) La fonction membre devient non statique.