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实例的地址。然后,为了启动下一个线程,再次在先前启动的线程的脚下修改该实例。作为一种补救措施,创建一个结构来保存必要的参数(主机,端口,this)和HANDLE。将此结构存储在std :: list中,然后将相应元素的地址传递给CreateThread()。

你的代码还有另一个问题,你应该检查返回值。如果您知道所有明显的错误都已被检测到,那么在某些代码上寻求帮助会更好。为此,使用例外是最容易的。后的CreateThread(),它应该可能被beginthread()代替,添加这些行:

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

在第二步骤中,创建专用异常类,从runtime_error衍生,其持有的win32错误代码(参见GetLastError函数( )),并在异常消息中包含文本错误描述(请参阅FormatString())。这可能听起来像很多代码,但你只写了一次,你可以在很多地方重复使用它。

最后,你的quitter()有两个问题。第一个是无限循环。假设你不需要关闭它们后把手,试试这个来代替:

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

你可以写为while循环,太多,但我个人更喜欢一个for循环,如果迭代次数基本上是固定的。当然,你仍然需要检查TerminateThread()和CloseHandle()的返回值。第二个问题是TerminateThread()是一个不好的主意,因为你可能会终止线程,但仍然没有完成。在网络上搜索“terminatethread harmful”。在这里,你所能做的就是等待它结束使用WaitForSingleObject()。

+0

非常感谢提示。也感谢您抽出宝贵时间来看看其他代码,并指出我犯的一些其他错误。 – Djeezus 2013-04-09 15:49:06