2

В настоящее время у меня очень странная проблема в некотором моем коде. Переменная, которая кажется прекрасной после того, как ее объявление повреждено сразу после этого, и это приводит к нарушению доступа (в основном указатель все еще указывает на одно и то же место, но память кажется нераспределенной). Я уверен, что проблема связана с многопоточным процессом, но я понятия не имею, что это такое, поскольку я совершенно новичок в многопоточности.Указатель освобождается вскоре после объявления в многопоточной функции

Вот код:

#include "Firewall.h" 
#include <Ws2tcpip.h> 

Firewall::Firewall(void) 
{ 
} 


Firewall::~Firewall(void) 
{ 
} 

void Firewall::parseFile(string filePath) 
{ 
    XMLNode xMainNode=XMLNode::openFileHelper(filePath.c_str(),"firewall"); 

    // Filtrage 
    XMLNode nodeFiltrage = xMainNode.getChildNode("filtrage"); 
    XMLNode currentNode; 

    for(int i=0; i < nodeFiltrage.nChildNode();i++) 
    { 
     currentNode = nodeFiltrage.getChildNode(i); 

     string nom = currentNode.getName(); 

     if(nom == "permettre") 
      mapFiltrage_.insert(pair<int,bool>(atoi(currentNode.getAttribute().lpszValue), true)); 

     else if(nom == "bloquer") 
      mapFiltrage_.insert(pair<int,bool>(atoi(currentNode.getAttribute().lpszValue), false)); 
    } 

    // Redirection 

    XMLNode nodeRedirection = xMainNode.getChildNode("redirection"); 
    XMLNode currentSubNode; 

    for(int i = 0; i < nodeRedirection.nChildNode(); i++) 
    { 
     currentNode = nodeRedirection.getChildNode(i); 
     currentSubNode = currentNode.getChildNode("source"); 

     SourceDestination source((string)currentSubNode.getAttribute("adresse"), atoi(currentSubNode.getAttribute("port"))); 

     currentSubNode = currentNode.getChildNode("destination"); 
     SourceDestination destination((string)currentSubNode.getAttribute("adresse"), atoi(currentSubNode.getAttribute("port"))); 

     mapRedirection_.insert(pair<SourceDestination, SourceDestination>(source,destination)); 

     pair<SourceDestination, SourceDestination> test; 
    } 


} 

void Firewall::initialiser() 
{ 
    std::map<int, bool>::iterator iterFiltrage = mapFiltrage_.begin(); 
    HANDLE handleThread; 

    std::string tempFiltrage = "localhost"; 
    thread_arg arg; 

    // Parcours et lancement des connexions de filtrage 
    while(iterFiltrage != mapFiltrage_.end()) 
    { 
     arg.port = (*iterFiltrage).first; 
     arg.host = tempFiltrage; 
     arg.objRef = this; 

     handleThread = CreateThread(NULL, 0, listenThread, &arg, 0, NULL); 
     listeThread_.push_back(handleThread); 

     iterFiltrage++; 
    } 

    // Parcours et lancement des connexions de redirection 
    std::map<SourceDestination, SourceDestination>::iterator iterRedirection = mapRedirection_.begin(); 

    while(iterRedirection != mapRedirection_.end()) 
    { 
     // Éviter la duplication inutile des sockets 
     if(mapFiltrage_.find((*iterRedirection).first.Port()) == mapFiltrage_.end()) 
     { 
      arg.host = (*iterRedirection).first.Host(); 
      arg.port = (*iterRedirection).first.Port(); 
      arg.objRef = this; 

      handleThread = CreateThread(NULL, 0, listenThread, &arg, 0, NULL); 
      listeThread_.push_back(handleThread); 
     } 

     iterRedirection++; 
    } 
} 


DWORD WINAPI Firewall::listenThread(LPVOID lpParam) 
{ 
    thread_arg* temp = (thread_arg*)lpParam; 
    Firewall* firewallRef = temp->objRef; 

    return firewallRef->runThread(lpParam); 
} 

DWORD Firewall::runThread(LPVOID lpParam) 
{ 
    thread_arg* infosSocket = (thread_arg*)lpParam; 

    // Créer le socket et l'attacher à la source 
    SOCKET sock = socket(AF_INET, SOCK_STREAM, 0); 

    if(sock == INVALID_SOCKET) 
    { 
     cout << "Erreur de creation de socket" << endl; 
     return EXIT_FAILURE; 
    } 

    //Recuperation de l'adresse locale 
    hostent *thisHost; 
    const char* test = infosSocket->host.c_str(); 
    thisHost=gethostbyname(test); 
    char* ip; 
    ip=inet_ntoa(*(struct in_addr*) *thisHost->h_addr_list); 

    SOCKADDR_IN sin; 
    sin.sin_addr.s_addr = inet_addr(ip); 
    sin.sin_family = AF_INET; 
    sin.sin_port = htons(infosSocket->port); 



    if(bind(sock, (SOCKADDR*)&sin, sizeof(sin)) == SOCKET_ERROR) 
    { 
     cout << "Erreur de binding" << endl; 
     return EXIT_FAILURE; 
    } 

    // Contexte du client 
    SOCKADDR_IN csin; 
    SOCKET csock; 
    socklen_t crecsize = sizeof(csin); 

    listeSocket_.push_back(sock); 
    listeSocket_.push_back(csock); 

    // Écouter sur le port 
    if(listen(sock, 5) == SOCKET_ERROR) 
    { 
     cout << "Erreur de listen" << endl; 
     return EXIT_FAILURE; 
    } 

    //csock = accept(sock, (SOCKADDR*)&csin, &crecsize); 

    return EXIT_SUCCESS; 
} 

void Firewall::quitter() 
{ 
    // Fermer les sockets 
    vector<SOCKET>::iterator iter1 = listeSocket_.begin(); 

    while(iter1 != listeSocket_.end()) 
    { 
     closesocket((*iter1)); 
     iter1++; 
    } 

    // Fermer les threads 

    vector<HANDLE>::iterator iter2 = listeThread_.begin(); 

    while(iter2 != listeThread_.end()) 
    { 
     TerminateThread((*iter2), EXIT_SUCCESS); 
     CloseHandle((*iter2)); 
    } 
} 

Большое спасибо.

ответ

1

Ваша проблема в этом коде:

thread_arg arg; 

loop(...) 
{ 
    arg = ...; 
    handleThread = CreateThread(..., &arg, ...); 
} 

Каждый поток начал здесь получает адрес одного и того же thread_arg экземпляра. Затем, для запуска следующего потока, вы снова модифицируете этот экземпляр под ногами ранее запущенного потока. В качестве средства создания создайте структуру, содержащую необходимые аргументы (хост, порт, это) и РУЧКУ для потока. Сохраните эту структуру в std :: list и затем передайте адрес соответствующего элемента CreateThread().

В коде есть еще одна проблема, вы должны проверить returnvalues. Гораздо приятнее обратиться за помощью к некоторому коду, если вы знаете, что все очевидные ошибки были обнаружены. Для этого проще использовать исключения. После CreateThread(), который, возможно, должен быть BeginThread() вместо того, чтобы добавить эти строки:

if(handleThread == NULL) 
    throw std::runtime_error("CreateThread() failed"); 

На втором этапе, создать специальный класс исключений, производный от runtime_error, который содержит код ошибки win32 (см GetLastError ()) и включает описание текстовой ошибки в сообщении об исключении (см. FormatString()). Это может показаться большим количеством кода для ничего, но вы только пишете это один раз, и вы можете его повторно использовать во многих местах.

И, наконец, ваш вопросник имеет две проблемы. Первый - это бесконечный цикл. Предполагая, что вы не нужны ручки после их закрытия, попробуйте вместо этого:

for(; listeThread_.empty(); listeTread_.pop_back()) 
{ 
    TerminateThread(listeThread_.back(), EXIT_SUCCESS); 
    CloseHandle(listeThread_.back()); 
} 

Вы можете написать это как в то время как контур, тоже, но я лично предпочитаю для цикла, если число итераций существенно неподвижная , Конечно, вам все равно нужно проверить возвращаемые значения TerminateThread() и CloseHandle(). Вторая проблема заключается в том, что TerminateThread() - плохая идея, потому что вы можете прекратить поток в середине чего-то, что остается наполовину выполненным. Найдите в Интернете «terminatethread вредный». Здесь вы можете только дождаться окончания работы WaitForSingleObject().

+0

Большое спасибо за совет. Также спасибо за то, что нашли время, чтобы посмотреть на остальную часть кода и указать на некоторые другие ошибки, которые я сделал. – Djeezus