Создается только один поток, несмотря на попытку создать два - PullRequest
0 голосов
/ 05 марта 2012
#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

Проблема в том, что создается впечатление, что создается только один поток! Я вызвал функцию checkServerExists 4 раза в main () и 2 раза с другим serverID, поэтому должны быть созданы два потока?

Что мне не хватает?

Ответы [ 4 ]

2 голосов
/ 05 марта 2012

РЕДАКТИРОВАНИЕ: реальная проблема заключается в том, что потоки завершаются и объединяются как как только они будут созданы, как указано hmjd. Я оставляю это, вместо того, чтобы удалить его, потому что следующие проблемы также являются проблемами.

В выводе, который вы публикуете, я вижу два создания новой темы: "In checkServerExists" выводится, только если вы создаете новую тему. Я также увидеть неопределенное поведение в printf: newThread имеет тип pthread_t, которым может быть все, что система хочет, и скорее всего, что-то отличное от long, что требуется формат, который вы передаете printf. Там, насколько я знаю, нет пути (переносимо) вывода pthread_t (кроме шестнадцатеричного дампа его байт); значения, которые вы отображаете как идентификаторы потоков, ничего не значат. Кроме того, вы не можете сравнить 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 голос
/ 05 марта 2012
      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.

(Возможно, вы захотите исправить некоторые ошибки, обнаруженные в этой теме, и опубликовать новый вопрос с обновленным кодом и описанием всех проблем, которые у вас остались с ним.)

1 голос
/ 05 марта 2012

Я не уверен, влияет ли это на поведение, но следующее является ошибкой:

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))

РЕДАКТИРОВАТЬ:

I думаю, это проблема: когда вызывается checkServerExists(), кажется, что он ждет потока, который он началдля завершения:

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

Это означает, что идентификатор потока 140233482061584 больше не используется и снова доступен для связи с новым потоком.При следующем вызове checkServerExists() идентификатор потока используется повторно, создавая впечатление, что был запущен только один поток.

РЕДАКТИРОВАТЬ 2:

Как указывает Шварц, это неверно:

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

вам нужно использовать pthread_equal() для сравнения двух pthread_t.Измените на:

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

или альтернативно передайте serverId в качестве аргумента потоку.

0 голосов
/ 05 марта 2012

Я понимаю, почему он не работает так, как вы ожидаете. Ваша серверная сторона использует уникальный идентификатор, переданный из main, чтобы определить, каким должен быть ее идентификатор потока, но сама функция потока использует идентификатор потока.

Первый созданный вами рабочий поток завершается, а второй создается с тем же идентификатором, что и первый, поскольку этот идентификатор теперь доступен.

Основной поток помещает строку в очередь второго элемента вектора, но ваш поток выбирает первый элемент вектора, потому что у него совпадает идентификатор потока.

Кстати, все, что они говорили в предыдущих постерах, тоже следует учитывать. Просто это не те, которые производят ваше поведение.

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

  // look through the queue
}

Измените тип коллекции на std::list или std::deque, чтобы он не делал недействительным указатель, если вы впоследствии сделаете push_back во время его обработки потоком.

В checkServerExists передайте адрес serverInfo в функцию потока, а не адрес идентификатора потока.

Вы также можете «проиндексировать» вашу коллекцию с помощью карты из int в serverInfo * или в итератор списка, если вы используете список. Вы не должны использовать std::map<int, serverInfo>, потому что это может сделать ваши указатели недействительными, если вы добавите новые записи на карту.

Кстати, ваш рабочий поток завершается слишком рано, потому что когда вы отправляете более позднюю информацию на старые идентификаторы, потоки уже исчезли.

Пустая очередь не должна быть условием завершения потока, и вы должны использовать другие средства.

Между прочим, хотя он является поточно-ориентированным, ваш мьютекс заблокирован так долго, что вы не сможете достичь приличной производительности при использовании нескольких потоков здесь.

...