Search code examples
c++multithreadingwinpcap

How to achieve the concurrency of two threads?


I write a program to capture the packets using Library "Winpcap". ( How to complie WinPcap with VS2010? Please see this link: http://www.rhyous.com/2011/11/12/how-to-compile-winpcap-with-visual-studio-2010/)

I want to capture the packet(using pcap_loop()) and at the same time I process the packet in the same function void D. The code int x = 1; in function void D is only an easy example which represents some functions that can process the packet. The thread t calls void D. The thread tt calls the function startCap() which captures the packet.

I want to emphasize my question: I debug the program and it stops at the position of pcap_loop() in thread tt until pcap_loop() finishes. I set the parameter of pcap_loop() to make it to run without end because I need continious capture of packet. The result is that the program will not go to the next step int x = 1;. I want to run int x = 1; as thread tt runs. In a word, I wish that the both threads t and tt run at the same time. But the program runs only on thread tt without jumping out and run on thread t.

PS 1: int x = 1; keeps staying better in void D.

PS 2: There's no erros in compiling and debuging. But the program falls into the function pcap_loop which is in the thread tt.

Did I make my question clear?

The whole code:

Data.h

#ifndef DATA_H
#define DATA_H

#include <pcap/pcap.h>
#include <vector>

using namespace std;

struct PcapDevice
{
    string name;
    string description;
};

class Data 
{

public:
    Data();
    ~Data();
    bool findDevices(vector<PcapDevice> &deviceList );
    bool openDevices(const char * device);
    void processPacket();
    void startCap();

private:
    pcap_t*         inData;
    char            errbuf[256];
    bool            isCapturing;
    pcap_if_t *     m_pDevs;
};

#endif // DATA_H

Data.cpp

    #include "Data.h"
    #include <iostream>

    // define pcap callback
    void capture_callback_handler(unsigned char *userData, const struct pcap_pkthdr* pkthdr, const unsigned char * packet)
    {
        ((Data*) userData)->processPacket();
    }

    Data::Data()
    {
        memset(errbuf,0,PCAP_ERRBUF_SIZE);
        isCapturing = false;
        inData = NULL;
        m_pDevs = NULL;
    }

    Data::~Data()
    {

    }

    // process the packet
    void Data::processPacket()
    {

    return ; 
    }
    // find local adapter
    bool Data::findDevices(vector<PcapDevice> &deviceList )
    {
        m_pDevs = NULL;

        int res = pcap_findalldevs(&m_pDevs, errbuf);
        if(0 == res)
        {
            pcap_if_t * pIter = m_pDevs;

            while(pIter != NULL)
            {
                PcapDevice device;
                device.description = pIter->description;
                device.name = pIter->name;
                deviceList.push_back(device);
                pIter = pIter->next;
            }
            return true;
        }
        else
        {
             printf("PCAP: no devices found\n");
        }

        return false;
    }
    // open the adapter
    bool Data::openDevices(const char *device)
    {   

        if ( (inData = pcap_open_live(device, 8192, 1,  512, errbuf)) == NULL)
        {

            return false;
        }

        return true;
    }
    // start the process of capturing the packet
    void Data::startCap()
    {
        if  ( inData == NULL ){
            fprintf(stderr, "ERROR: no source set\n" );
            return;
        }
        // free the list of device(adapter) 
        pcap_freealldevs(m_pDevs);
        Data* data = this;
        isCapturing = true;
        // capture in the loop
        if ( pcap_loop(inData, -1, capture_callback_handler, (unsigned char *) data) == -1)
        {
            fprintf(stderr, "ERROR: %s\n", pcap_geterr(inData) );
            isCapturing = false;
        }
    }

main.cpp

#include <WinSock2.h>
#include <Windows.h>
#include <time.h>
#include "Data.h"
#include <boost\thread\thread.hpp>
#include <boost\function.hpp>

struct parameter
{
   Data* pData;
};
void D(void* pParam)
{
    // init the parameter 
    parameter* pUserParams = (parameter*)pParam;
    boost::function<void()> f;
    // the capture thread will be started
    f = boost::bind(&Data::startCap, pUserParams->pData);   
    boost::thread tt(f);
    tt.join();

   // I want to work on the packet at the same time,  the code "int x=1" is only an easy example  
   // and it represents a series of functions that can process the packet. I want to run those function as the thread tt runs. 
    int x = 1;
}


void main()
{
   Data oData;
   parameter pPara ;
   pPara.pData = &oData;
   std::vector<PcapDevice>    DevList;  
   oData.findDevices(DevList);
   int num = DevList.size()-1;
   oData.openDevices(DevList[num].name.c_str());
   boost::thread t(D,(void*)&pPara);
   t.join();
}

Solution

  • Calling tt.join() will wait until the thread finishes (that is, startCap() returns) before executing the next statement.

    You can simply put your int x = 1; before the join(); however, the thread may have not have even started at that point. If you want to ensure the thread is running, or up to a certain point before processing int x = 1; you can use a condition_variable:

    The condition_variable class is a synchronization primitive that can be used to block a thread, or multiple threads at the same time, until:

    • a notification is received from another thread
    void Data::startCap(std::condition_variable& cv)
    {
        if  ( inData == NULL ){
            fprintf(stderr, "ERROR: no source set\n" );
            return;
        }
        // free the list of device(adapter) 
        pcap_freealldevs(m_pDevs);
        Data* data = this;
        isCapturing = true;
    
        // Notify others that we are ready to begin capturing packets
        cv.notify_one();
    
        // capture in the loop
        if ( pcap_loop(inData, -1, capture_callback_handler, (unsigned char *) data) == -1)
        {
            fprintf(stderr, "ERROR: %s\n", pcap_geterr(inData) );
            isCapturing = false;
        }
    }
    
    void D(void* pParam)
    {
        // init the parameter 
        parameter* pUserParams = (parameter*)pParam;
    
        // Create conditional_variable
        std::conditional_variable cv;
    
        // Pass the conditional_variable by reference to the thread
        boost::thread tt(&Data::startCap, pUserParams->pData, std::ref(cv));
        // Wait until the thread notifies us it's ready:
        cv.wait();
    
        // Process packets etc.
        int x = 1;
    
        // Wait for the thread to finish
        tt.join();
    }
    

    Now D() will start the thread tt and then wait until startCaps has reached a certain point (where it calls notify_one()) before we continuing doing things.