尽管尝试创建两个线程,但只创建了一个线程

时间:2012-03-05 09:51:25

标签: c++ pthreads mutex race-condition

#include <pthread.h>
#include <stdio.h>
#include <unistd.h>
#include <vector>
#include <string>
#include <iostream>

FILE*            fp;
pthread_mutex_t demoMutex         = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t  conditionVariable = PTHREAD_COND_INITIALIZER;
unsigned int    condition         = 0;

struct serverInfo
{
    unsigned int serverId;
    pthread_t    threadId;
    std::vector<std::string> queue;
};
std::vector<serverInfo> serverInfoVector;

void* printHello(void* threadId)
{
    pthread_t* my_tid = (pthread_t*)threadId;

    pthread_mutex_lock(&demoMutex);
    while (condition == 0)
        pthread_cond_wait(&conditionVariable, &demoMutex);

    unsigned int i = 0;
    char found = false;

    if (serverInfoVector.size () > 0) {
       while ((i <= serverInfoVector.size()) && (found == false)) {
          if (*my_tid == serverInfoVector[i].threadId) {
             found = true;
             break;
          }
          else
             i++;
       }
    }

    while (!serverInfoVector[i].queue.empty()) {
       std::cout << "\nThread: " << pthread_self() << ", poped from queue: " << serverInfoVector[i].queue.front();
       serverInfoVector[i].queue.pop_back();
    }

    pthread_mutex_unlock(&demoMutex);
    pthread_exit(NULL);
}

void checkServerExists(unsigned int serverNumber, std::string message)
{
    unsigned int i = 0;
    char found = false;

    pthread_mutex_lock(&demoMutex);

    if (serverInfoVector.size () > 0) {
       while ((i <= serverInfoVector.size()) && (found == false)) {
          if (serverNumber == serverInfoVector[i].serverId) {
             found = true;
             break;
          }
          else
             i++;
       }
    }

    if (found == false) {
       // This server doesn't exist, so create a thread for it, create a queue for it, push the message in the corresponding queue.
       // Push the server number in the serverNumberArray.

       // Create a thread for it.
       pthread_t newThread;
       int returnValue;
       if ((returnValue = pthread_create (&newThread, NULL, printHello, (void*) &newThread)) != 0) {
          printf("\nerror: pthread_create failed with error number %d", returnValue);
       }
       printf("\nIn checkServerExists()`: thread id %ld\n", newThread);

       // Push the message in its queue.
       serverInfo obj;
       obj.serverId = serverNumber;
       obj.threadId = newThread;
       obj.queue.push_back(message);
       serverInfoVector.push_back(obj);

       condition++;
       pthread_cond_signal(&conditionVariable);
       pthread_mutex_unlock(&demoMutex);

       for (unsigned int i = 0; i < serverInfoVector.size(); i++)
          pthread_join(serverInfoVector[i].threadId, NULL);
    }
    else {
       // This server exists, so lookup its thread and queue, push the message in the corresponding queue.
       printf("\nIn else ()`: thread id %ld\n", serverInfoVector[i].threadId);
       serverInfoVector[i].queue.push_back(message);

       condition++;
       pthread_cond_signal(&conditionVariable);
       pthread_mutex_unlock(&demoMutex);

       for (unsigned int i = 0; i < serverInfoVector.size(); i++)
          pthread_join(serverInfoVector[i].threadId, NULL);
    }
}

int main()
{
   fp = fopen("xyz", "w");

   checkServerExists(1, "anisha");
   checkServerExists(2, "kaul");
   checkServerExists(1, "sanjeev");
   checkServerExists(2, "sharma");
}

输出:

In checkServerExists ()`: thread id 140233482061584

Thread: 140233482061584, poped from queue: anisha
In checkServerExists ()`: thread id 140233482061584

In else ()`: thread id 140233482061584

In else ()`: thread id 140233482061584

问题是似乎只创建了一个线程!我在main()中调用了函数checkServerExists 4次,在不同的serverID中调用了2次,因此应该创建两个线程吗?

我错过了什么?

4 个答案:

答案 0 :(得分:2)

编辑:真正的问题是线程终止并加入为 正如hmjd所指出的那样。我要离开这个, 而不是删除它,因为以下也是问题。

我在您发布的输出中看到两个新线程的创建:"In checkServerExists"仅在您创建新线程时输出。我也 请参阅printf中的未定义行为:newThread具有类型 pthread_t,可以是系统想要的任何东西,而且是 可能是long以外的其他东西,这是所需要的 您传递给printf的格式。据我所知,没有办法 (可移植地)输出pthread_t(除了它的十六进制转储) 字节);您显示为线程ID的值并不意味着什么。 另外,您无法比较pthread_t使用==,您需要使用 pthread_equal。 (至少在我使用的一个平台上,pthread_t是一个 struct。)

您的代码还有许多其他奇怪的事情。为什么要申报 例如,found类型为char,而不是类型bool。为什么呢 found == false,而不是!found。为什么break;在 循环,因为你在循环控制变量中有条件。很多 更checkServerExists开头的惯用形式将是:

for ( std::vector<ServerInfo>::iterator current = serverInfoVector.begin();
        current != serverInfoVector.end() && current->serverId != serverNumber;
        ++ current ) {
}
if ( current == serverInfoVector.end() ) {
    //  not found...
} else {
    //  found...
}

假设您没有为查找创建谓词对象,只是 使用std::find

答案 1 :(得分:1)

我不确定这是否有助于此行为,但以下是错误:

while ((i <= serverInfoVector.size ()) && (found == false))
{
    if (serverNumber == serverInfoVector [i].serverId)
    {
        found = true;
        break;
    }
    else
        i++;
}
由于serverInfoVector[i]中的<=条件,

if将访问太多。改为:

while ((i < serverInfoVector.size ()) && (found == false))

编辑:

认为这就是问题:当调用checkServerExists()时,似乎等待它开始完成的线程:

for (unsigned int i = 0; i < serverInfoVector.size(); i++)
    pthread_join(serverInfoVector[i].threadId, NULL);

这意味着线程标识140233482061584不再使用,并且可以再次与新线程关联。当下一次调用checkServerExists()时,重新使用线程ID,给人的印象是只启动了一个线程。

编辑2:

正如施瓦茨所指出的,这是不正确的:

if (*my_tid == serverInfoVector[i].threadId) {

您需要使用pthread_equal()来比较两个pthread_t。改为:

if (pthread_equal(*my_tid, serverInfoVector[i].threadId)) {

或者将serverId作为参数传递给线程。

答案 2 :(得分:1)

      if (*my_tid == serverInfoVector[i].threadId) {

你不能用这种方式比较pthread_t。这是一个C接口,而不是C ++接口。因此没有操作员超载来使这种比较合理地工作。出于同样的原因这是错误的:

    const char *foo="foo";
    if(foo == "foo") ...

你必须使用合理的比较功能。在我的示例中,strcmp。在您的代码中pthread_equal

此外,在您pthread_join一个帖子后,其pthread_t不再有效。您不能再将其传递给任何pthread_*函数。这与将指针传递给free后取消引用一样糟糕。

(您可能需要修复此主题中报告的所有错误,并使用您更新的代码发布新问题,并说明您仍然遇到的任何问题。)

答案 3 :(得分:0)

我可以理解为什么它没能像你期望的那样工作。你的服务器端使用从main传入的唯一标识符来确定它的线程id应该是什么,但是线程函数本身使用的是线程id。

您创建的第一个工作线程已终止,第二个工作线程的ID与第一个相同,因为此ID现已可用。

主线程将字符串放在向量中第二个元素的队列中,但是你的线程正在拾取向量的第一个元素,因为它有一个匹配的线程id。

顺便提一下,他们以前的海报所说的所有东西也应该被考虑。只是因为它不是产生你行为的那些。

void* printHello(void* serverptr) 
{ 
    serverInfo * info = static_cast< serverInfo * >(serverptr);

  // look through the queue
}

将集合类型更改为std::liststd::deque,这样如果您在线程处理它时随后执行了push_back,它将不会使指针无效。

checkServerExists中,将serverInfo的地址传递给线程函数而不是thread_id的地址。

你也可以&#34;索引&#34;您的集合使用从int到serverInfo *的映射,或者如果使用列表,则使用列表迭代器。您不应该使用std::map<int, serverInfo>,因为如果您向地图添加新条目,它可能会使您的指针无效。

顺便提一下,你的工作线程看起来太早终止,因为当你将后来的信息发送到旧的ID时,线程已经消失了。

队列为空不应该是终止线程的条件,你应该使用其他方法。

顺便提一下,虽然它是线程安全的,但你的互斥锁被锁定了很长时间,以至于你不会通过在这里使用多个线程来实现任何不错的性能。