消费者生产商Thread Issue

时间:2011-03-03 07:49:20

标签: c++ winapi

我正在研究Single Producer Single Consumer Problem.Here producer thread将写入列表,而消费者线程将其从列表中删除。 我有对话框,我在其中维护两个列表1.consumer列表框2.producer列表框,它将列出两个线程发布的消息。我在这里遇到奇怪的问题。这些消息是相互混淆的。消费者线程是除了消费者线程消息线程之外,还获得Producer的消息,反之亦然。

我从主线传递THREADINFO

任何机构都可以告诉我这里出了什么问题。我从主线程传递正确的线程名称,但是当涉及到生产者或消费者线程时,某些时候值会发生变化。 我在下面给出了两个帖子

typedef struct THREADINFO{  
    CEventQueue* pEventQueue;
    HWND hWndHandle;
    char* pThreadName;
}THREADINFO
DWORD WINAPI    ProducerThrdFunc ( LPVOID n )
{
    THREADINFO* stThreadInfoProd = (THREADINFO*)n;
    char* pMsg1 = new char[100];
    while(1)
    {

        strcpy(pMsg1,stThreadInfoProd->pThreadName);
        strcat(pMsg1," Thread No:");        
        strcat(pMsg1,"Adding Msg");

        PostMessage(stThreadInfoProd->hWndHandle,UWM_ONUPDATEPRODUCERLIST,(WPARAM)pMsg1,0);

        stThreadInfoProd->pEventQueue->AddTail(pMsg1);
        memset(pMsg1,0,100);

        strcpy(pMsg1,stThreadInfoProd->pThreadName);
        strcat(pMsg1,"Thread No:");     
        strcat(pMsg1,"Added Msg");
        char*p = "Producer";
        PostMessage(stThreadInfoProd->hWndHandle,UWM_ONUPDATEPRODUCERLIST,(WPARAM)pMsg1,0);

        Sleep(3000);
    }   
    return 0;
}

DWORD WINAPI    ConsumerThrdFunc ( LPVOID n )
{
    THREADINFO* stThreadInfoCons = (THREADINFO*)n;

    char* pMsg = new char[100];
    memset(pMsg,0,100);

    while(1)
    {
        strcpy(pMsg,stThreadInfoCons->pThreadName);
        strcat(pMsg," Thread No:");
        strcat(pMsg,"Removing Msg");        
        PostMessage(stThreadInfoCons->hWndHandle,UWM_ONUPADTECONSUMERLIST,(WPARAM)pMsg,0);

        memset(pMsg,0,100);

        char *pMsg = (char*)stThreadInfoCons->pEventQueue->RemoveHead();        
        strcpy(pMsg,stThreadInfoCons->pThreadName);
        strcat(pMsg,"Thread No:");
        strcat(pMsg,"Removed Msg");

        PostMessage(stThreadInfoCons->hWndHandle,UWM_ONUPADTECONSUMERLIST,(WPARAM)pMsg,0);
        Sleep(3000);
    }
    return 0;
}

2 个答案:

答案 0 :(得分:0)

你的THREADINFO结构是如何构建的?在您创建结构的函数中的本地堆栈上,在堆栈的全局级别上,还是在堆上? 在THREADINFO实例加入工作线程之前,它可能会超出范围。

答案 1 :(得分:0)

此代码存在很多问题。

在您的生产者主题中,您正在执行以下操作:

stThreadInfoProd->pEventQueue->AddTail(pMsg1);

除非AddTail很聪明,否则这是添加指向队列的指针,它不会复制字符串。然后,在您的消费者中,您正在这样做:

char *pMsg = (char*)stThreadInfoCons->pEventQueue->RemoveHead();

获取您添加到队列中的指针。这指向您用于生成器消息的缓冲区,因此当您在使用者中执行此操作时:

strcpy(pMsg,stThreadInfoCons->pThreadName);
strcat(pMsg,"Thread No:");
strcat(pMsg,"Removed Msg");

你正在覆盖制作人的缓冲区。我想你想要的更像是这样:

char *pProducerMsg = (char*)stThreadInfoCons->pEventQueue->RemoveHead();

然后以下行不会覆盖生产者的数据。

但这引入了另一个问题。在您的制作人中,您可以这样做:

stThreadInfoProd->pEventQueue->AddTail(pMsg1);

将指针添加到队列中,然后立即执行此操作:

memset(pMsg1,0,100);
strcpy(pMsg1,stThreadInfoProd->pThreadName);
strcat(pMsg1,"Thread No:");     
strcat(pMsg1,"Added Msg");

覆盖缓冲区。这种覆盖几乎肯定会在消费者有机会使用消息之前发生,因此消费者将读取修改后的缓冲区,而不是您最初发送的消息。要解决这个问题,请改变生产者:

stThreadInfoProd->pEventQueue->AddTail(strdup(pMsg1));

strdup创建pMsg1指向的缓冲区内容的副本。

然后消费者需要:

char *pProducerMsg = (char*)stThreadInfoCons->pEventQueue->RemoveHead();
// do something with pProducerMsg
free (pProducerMsg); // strdup calls malloc, so a matching free is required