【问题标题】:C++ Win32 data processing threadC++ Win32数据处理线程
【发布时间】:2015-08-05 12:08:57
【问题描述】:

我编写了一个 Win32 异步客户端应用程序,我想创建一个线程来分别处理传入的数据。我对以下代码有疑问。线程启动,获取一些数据但没有正常运行(数据不完整)。我看不出问题出在哪里。你能帮帮我吗?

void incData(void *arg) // This is the thread
{
    WaitForSingleObject(hIncDataMutex, INFINITE);

    char *sRead = _strdup(sReadBuffer.c_str());
    appendTextToEdit(hDebug, sRead); // Some data is displayed, but incompletely
    string var;
    char *pVar = nullptr;                   
    char *next_token = nullptr;

    istringstream iss(sReadBuffer); // sReadBuffer is the global variable I use to pass argument to my thread   

    while (getline(iss, var)) // Default delimiter '\n'
    {       
        pVar = _strdup(var.c_str()); // Cast string to char *
        appendTextToEdit(hDebug, pVar);
        appendTextToEdit(hDebug, "\n");

        if(strstr(pVar, "id=") != NULL)
        {   
            char *label = strtok_s(pVar, "=", &next_token);                     
            char *pId = strtok_s(NULL, "\n", &next_token);                          
            strcpy_s(id, pId);
        }

        if( strstr(pVar, "version") != NULL)
        {
            char *label = strtok_s(pVar, "=", &next_token);                     
            char *pVersion = strtok_s(NULL, "\n", &next_token);                     
            strcpy_s(version, pVersion);                        
        }       

        if( strstr(pVar, "Qh57=") != NULL)
        {
            char *label = strtok_s(pVar, "=", &next_token);     
            char *pFoFd = strtok_s(NULL, "\n", &next_token);                            
            strcpy_s(foFd, pFoFd);          
        }
    }
    ReleaseMutex(hIncDataMutex);
}

//.....

case FD_CONNECT: // I launch the thread here (I want it to run forever in the background)
{
    connectStatus = TRUE;
    statusText=TEXT("Connected");               

    hIncDataMutex = CreateMutex(NULL, false, NULL); // Create incoming data process thread mutex
    HANDLE hThread2 = (HANDLE)_beginthread(incData, 0, 0); // Launch incoming data process thread
}

//....

case FD_READ:
{   
    int bytes_recv = recv(Socket, readBuffer, sizeof(readBuffer), 0);               

    sReadBuffer = readBuffer; // Copy the buffer to global scope string (used to feed thread)               

    ReleaseMutex(hIncDataMutex);
}
break;

编辑

这是我的代码,带有新的调试行,以及调试窗口的输出:

void incData(void *arg)
{
WaitForSingleObject(hIncDataMutex, INFINITE);
appendTextToEdit(hDebug, "Inside thread...\n");


string var;
char *pVar = nullptr;                   
char *next_token = nullptr;

istringstream iss(sReadBuffer); // Put into a stream            

while (getline(iss, var)) // Default delimiter '\n'
{       
    pVar = _strdup(var.c_str()); // Cast string to char *       

    if(strstr(pVar, "id=") != NULL)
    {   
        char *label = strtok_s(pVar, "=", &next_token);                     
        char *pId = strtok_s(NULL, "\n", &next_token);                          
        strcpy_s(id, pId);
    }

    if( strstr(pVar, "version") != NULL)
    {
        char *label = strtok_s(pVar, "=", &next_token);                     
        char *pVersion = strtok_s(NULL, "\n", &next_token);                     
        strcpy_s(version, pVersion);                        
    }       

    if( strstr(pVar, "Qh57=") != NULL)
    {
        char *label = strtok_s(pVar, "=", &next_token);     
        char *pFoFd = strtok_s(NULL, "\n", &next_token);                            
        strcpy_s(foFd, pFoFd);
        appendTextToEdit(hDebug, "Qh57=");
        appendTextToEdit(hDebug, foFd);
        appendTextToEdit(hDebug, "\n"); 
    }
}

ReleaseMutex(hIncDataMutex);
appendTextToEdit(hDebug, "Mutex released by thread\n");
}

//....

case FD_READ:
            {   
                appendTextToEdit(hDebug, "FD_READ event\n");            


                int bytes_recv = recv(Socket, readBuffer, sizeof(readBuffer), 0);                   
                appendTextToEdit(hDebug, "Bytes reveived\n");
                sReadBuffer = readBuffer; // Copy the buffer to string
                ReleaseMutex(hIncDataMutex);
                appendTextToEdit(hDebug, "End of FD_READ\n");
            }
            break;

从调试窗口:

FD_CONNECT, begining thread
FD_READ event
Bytes reveived
End of FD_READ
FD_READ event
Bytes reveived
End of FD_READ
Inside thread... // Thread is only called here !
FD_READ event
Bytes reveived
End of FD_READ
Mutex released by thread // Thread ends here
FD_READ event
Bytes reveived
End of FD_READ

等等... 有什么想法吗?

【问题讨论】:

  • 字符 0x00 是否出现在 readBuffer 的某处?在这种情况下,sReadBuffer = readBuffer; 中的 string::operator=char *sRead = _strdup(sReadBuffer.c_str()); 中的 _strdup 将仅复制缓冲区的开头直到字符 0x00。
  • 不,不,不!您正在到处复制缓冲区,包括进入/退出全局变量。该线程为其整个处理运行持有一个互斥锁。线程不断被创建/终止/销毁。难怪事情进展得很糟糕:(
  • 声明一个缓冲区类,可能带有一个向量来保存数据。创建一个实例,(新),加载数据,使用生产者-消费者队列向线程发送实例信号。只启动线程一次,让它在 P-C 队列弹出周围循环,等待缓冲区实例并在它们到达时处理它们。

标签: c++ multithreading winapi client


【解决方案1】:

我认为这是因为您在互斥体上等待数据的方式:将其设置在一侧并且从不尝试将其设置在另一侧清楚地表明缺少某些内容。

以下是可能发生的情况:

main thread                         processing thread
--------------------------------------------------
data A is received on FD_READ        waiting on mutex 
ReleaseMutex() --->                  start processing the data A
other data B is received                .. 
ReleaseMutex()                          .. end processing data A
still other C data overwrites B      ReleaseMutex()     
ReleaseMutex()                       waiting on mutex
                                     processing data C which has overwriten B
                                     ( ==> B is lost) 

避免接收数据,除非您可以以一种不会覆盖尚未处理的数据的方式对其进行缓冲。这通常需要在更新(填充)共享数据时(即在尝试复制缓冲区之前)设置 mutext。至少从设计原则来看,This tutorial 可能是您感兴趣的或感兴趣的。

重要修改:

与多线程无关,但不要忘记recv() 不保证以空值结尾的字符串。因此,在将其复制到字符串之前,请检查错误并在结尾添加一个 '\0'。因此,作为第一步,您可以尝试:

case FD_READ:
{   
    int bytes_recv = recv(Socket, readBuffer, sizeof(readBuffer),
0); 
    if (bytes_recv!=SOCKET_ERROR) {
        readBuffer[bytes_recv] = '\0'; //... trailing null 
        WaitForSingleObject(hIncDataMutex, INFINITE);
        sReadBuffer = readBuffer; // Copy the buffer to global scope string (used to feed thread)               

        ReleaseMutex(hIncDataMutex);

    }
    else cout << "Socket error"; 
    ...              

【讨论】:

  • 非常感谢您的帮助。不幸的是,我不知道如何在我的代码中实施您的建议。我想我必须再次学习线程:-(
  • 作为第一步,我建议在case FD_READ 中添加WaitForSingleObject(hIncDataMutex, INFINITE);,就在` sReadBuffer = readBuffer;`行之前
  • 已经试过了。它使我的程序挂起......我的缓冲区肯定被覆盖了。但我不知道如何避免这种情况并同步所有内容。
  • 程序挂在哪里?您能否尝试进一步分析(记录)它挂在哪里?
  • 好的。我调查并记录了更多信息。在调用线程之前,程序会进行 3 或 4 个 FD_READ “循环”。
猜你喜欢
  • 2011-01-29
  • 1970-01-01
  • 2013-08-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-10-24
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多