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

Only one thread gets created despite the attempt to create two

本文关键字:线程 创建 一个 两个      更新时间:2023-10-16
#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 %ldn", 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 %ldn", 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((中调用了该函数4 checkServerExists,使用不同的serverID调用了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 .

我不确定这是否会导致行为,但以下是一个错误:

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

由于if中的<=条件,serverInfoVector[i]将访问太多。更改为:

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

编辑:

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

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

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

编辑2:

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

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

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

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

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

      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后取消引用指针一样糟糕。

(您可能希望修复此线程中报告的一些所有错误,并发布一个新问题,其中包含更新的代码以及您仍然存在的任何问题的描述。

我明白为什么它无法按您的期望工作。您的服务器端正在使用从 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的地址。

您还可以使用从 int 到 serverInfo* 或列表迭代器的映射(如果使用列表(来"索引"集合。但是,不应使用std::map<int, serverInfo>因为如果向地图添加新条目,指针可能会失效。

顺便说一下,您的工作线程似乎过早终止,因为当您将后面的信息发送到旧 id 时,线程已经消失了。

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

顺便说一下,虽然它是线程安全的,但您的互斥锁被锁定了很长时间,以至于您在这里使用多个线程并不能真正实现任何体面的性能。