Как установить pthread_cond_signal, чтобы программа не зависала? - PullRequest
1 голос
/ 16 февраля 2012

РЕДАКТ. 1:

FILE            *fp;
pthread_mutex_t demoMutex;
unsigned short globalThreadIndex = 0;

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

std :: vector <serverInfo> serverInfoVector;


void * printHello (void* threadId)
{
    pthread_t *my_tid = (pthread_t *)&threadId;
    printf ("\nIn `printHello ()`: thread id %ld\n", pthread_self ());

    ***pthread_mutex_lock (&demoMutex);***

    unsigned int i = 0;
    char               found = false;

    if (serverInfoVector.size () > 0)
    {
        // The following code should be executed when and only when the vector isn't empty.
        ***pthread_cond_wait (&demoConditionVar, &demoMutex);***

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

        if (found == true)
        {
            pthread_t            writeToFile = pthread_self ();
            unsigned short iterate;
            for (iterate = 0; iterate < 10000; iterate++)
            {
                fprintf (fp, " %d %d",  iterate,         4);
                fprintf (fp, " %lu %lu", writeToFile, sizeof (pthread_t));

                if (!serverInfoVector [i].queue.empty ())
                {
                    fprintf (fp, " %c %u", 'A', 1);
                    fprintf (fp, " %lu %lu", serverInfoVector [i].queue.front (), sizeof (pthread_t));
                    serverInfoVector [i].queue.pop_back ();
                }
                fprintf (fp, "\n %lu %u", writeToFile, 1);
            }
        }
        ***pthread_mutex_unlock (&demoMutex);***
        }
    ***pthread_exit (NULL);***
}

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

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

    if (found == false)
    {
        pthread_t newThread [2];

        int           returnValue;
        if ((returnValue = pthread_create (&newThread [globalThreadIndex], NULL, printHello, (void*) &newThread [globalThreadIndex])) != 0)
        {
          printf ("\nerror: pthread_create failed with error number %d", returnValue);
        }
        printf ("\nIn checkServerExists ()`: thread id %ld\n", newThread [globalThreadIndex]);

        serverInfo obj;
        obj.serverId  = serverNumber;
        obj.threadId = newThread [globalThreadIndex];
        obj.queue.push_back (newThread [globalThreadIndex]);
        serverInfoVector.push_back (obj);

        // Now, since something has been pushed in the vector, it makes sense to wake up the sleeping thread.
        ***pthread_mutex_lock (&demoMutex)***; 
        // Now, since something has been pushed in the vector, it makes sense to wake up the sleeping thread.
        if (serverInfoVector.size () > 0)
            ***pthread_cond_signal (&demoConditionVar);***

        ***pthread_mutex_unlock(&demoMutex);*** 

        pthread_join (newThread [globalThreadIndex], NULL);
    }
    else
    {
    }
}


int main ()
{
    fp = fopen ("xyz", "w");
    ***pthread_mutex_init (&demoMutex, NULL);
    pthread_cond_t demoConditionVar = PTHREAD_COND_INITIALIZER;***

    checkServerExists (1, "anisha");
    globalThreadIndex++;
    checkServerExists (2, "anisha");

    return 0;
}

Этот код улучшен, проблема все еще существует (программа зависает, второй поток не отображается).Функция

checkServerExists (в текущем случае) вызывает создание нового потока и сохранение его в массиве newThread.

checkServerExists функция запускает новый поток,

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

*Затем функция 1016 * вводит значение в очередь глобальной структуры, устанавливает сигнал для пробуждения потока.

Теперь, в чем смысл, которого я пропускаю?

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

FILE            *fp;
pthread_mutex_t demoMutex;
unsigned short globalThreadIndex = 0;

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

std :: vector <serverInfo> serverInfoVector;


void * printHello (void* threadId)
{
    pthread_t *my_tid = (pthread_t *)&threadId;
    printf ("\nIn `printHello ()`: thread id %ld\n", pthread_self ());

    ***pthread_mutex_lock (&demoMutex);***

    unsigned int i = 0;
    char               found = false;

    if (serverInfoVector.size () > 0)
    {
        // The following code should be executed when and only when the vector isn't empty.
        ***pthread_cond_wait (&demoConditionVar, &demoMutex);***

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

        if (found == true)
        {
            pthread_t            writeToFile = pthread_self ();
            unsigned short iterate;
            for (iterate = 0; iterate < 10000; iterate++)
            {
                fprintf (fp, " %d %d",  iterate,         4);
                fprintf (fp, " %lu %lu", writeToFile, sizeof (pthread_t));

                if (!serverInfoVector [i].queue.empty ())
                {
                    fprintf (fp, " %c %u", 'A', 1);
                    fprintf (fp, " %lu %lu", serverInfoVector [i].queue.front (), sizeof (pthread_t));
                    serverInfoVector [i].queue.pop_back ();
                }
                fprintf (fp, "\n %lu %u", writeToFile, 1);
            }
        }
        ***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].threadId)
            {
                found = true;
                break;
            }
            else
                i++;
        }
    }

    if (found == false)
    {
        pthread_t newThread [2];

        int           returnValue;
        if ((returnValue = pthread_create (&newThread [globalThreadIndex], NULL, printHello, (void*) &newThread [globalThreadIndex])) != 0)
        {
              printf ("\nerror: pthread_create failed with error number %d", returnValue);
        }
        printf ("\nIn checkServerExists ()`: thread id %ld\n", newThread [globalThreadIndex]);

        serverInfo obj;
        obj.serverId  = serverNumber;
        obj.threadId = newThread [globalThreadIndex];
        obj.queue.push_back (newThread [globalThreadIndex]);
        serverInfoVector.push_back (obj);

        // Now, since something has been pushed in the vector, it makes sense to wake up the sleeping thread.

        // Now, since something has been pushed in the vector, it makes sense to wake up the sleeping thread.
        if (serverInfoVector.size () > 0)
            ***pthread_cond_signal (&demoConditionVar);***


        pthread_join (newThread [globalThreadIndex], NULL);
    }
    else
    {
    }
        ***pthread_mutex_unlock(&demoMutex);*** 
}


int main ()
{
    fp = fopen ("xyz", "w");
    ***pthread_mutex_init (&demoMutex, NULL);
    pthread_cond_t demoConditionVar = PTHREAD_COND_INITIALIZER;***

    checkServerExists (1, "anisha");
    globalThreadIndex++;
    checkServerExists (2, "anisha");

    return 0;
}

В этом редакторе я поместил блокировку в верхней части функции checkServerExists (эта функция имеет дело с глобальной структурой serverInfoVector)

Все еще висит,: DOH:

Ответы [ 2 ]

5 голосов
/ 16 февраля 2012

Этот код не работает.

Во-первых, вы изменяете переменные внутри checkServerExists без блокировки мьютекса.Это неопределенное поведение.

Если вы исправите это, то вы также не будете сигнализировать свою переменную условия вне функции printHello.Следовательно, как только поток заблокирован в вызове pthread_cond_wait, он будет активирован только из-за ложных пробуждений, и когда другой поток printHello сообщит об этом.Вы должны вызывать pthread_cond_signal в том месте, где установлен флаг condition, а не в printHello.

Переменная условия - это просто механизм уведомления.Вам нужно связать с ним предикат, который является условием, которого ожидают (в вашем случае, condition!=0).Вы должны убедиться, что переменные, к которым обращаются при установке и тестировании условия, защищены мьютексом, и что этот мьютекс передается в pthread_cond_wait, чтобы избежать возможных состояний гонки.Когда вы устанавливаете переменные, чтобы указать, что спящий поток должен проснуться, вы вызываете pthread_cond_signal.

Я немного изменил ваш код, чтобы он работал.В частности, я поместил цикл вокруг вызова pthread_cond_wait и разблокировал мьютекс перед вызовом pthread_join, чтобы поток printHello мог получить мьютекс и продолжить.Вы никогда не должны удерживать блокировку мьютекса через соединение потоков.Этот код все еще может быть значительно улучшен - помимо прочего, он не является безопасным для исключения.

#include <pthread.h>
#include <stdio.h>
#include <vector>
#include <string>
FILE            *fp;
pthread_mutex_t demoMutex;
pthread_cond_t demoConditionVar;

unsigned short globalThreadIndex = 0;

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

std :: vector <serverInfo> serverInfoVector;

void * printHello (void* threadId)
{
    pthread_t *my_tid = (pthread_t *)threadId;
    printf ("\nIn `printHello ()`: thread id %ld\n", pthread_self ());

    pthread_mutex_lock (&demoMutex);

    unsigned int i = 0;
    bool found = false;

    while (serverInfoVector.empty())
        pthread_cond_wait (&demoConditionVar, &demoMutex);

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


    if (found)
    {
        pthread_t            writeToFile = pthread_self ();
        unsigned short iterate;
        for (iterate = 0; iterate < 10000; iterate++)
        {
            fprintf (fp, " %d %d",  iterate,         4);
            fprintf (fp, " %lu %lu", writeToFile, sizeof (pthread_t));

            if (!serverInfoVector [i].queue.empty ())
            {
                fprintf (fp, " %c %u", 'A', 1);
                fprintf (fp, " %lu %lu", serverInfoVector [i].queue.front (), sizeof (pthread_t));
                serverInfoVector [i].queue.pop_back ();
            }
            fprintf (fp, "\n %lu %u", writeToFile, 1);
        }
    }
    pthread_mutex_unlock (&demoMutex);
    pthread_exit (NULL);
}

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

    pthread_mutex_lock (&demoMutex);

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

    if (!found)
    {
        pthread_t newThread [2];

        int           returnValue;
        if ((returnValue = pthread_create (&newThread [globalThreadIndex], NULL, printHello, (void*) &newThread [globalThreadIndex])) != 0)
        {
            printf ("\nerror: pthread_create failed with error number %d", returnValue);
        }
        printf ("\nIn checkServerExists ()`: thread id %ld\n", newThread [globalThreadIndex]);

        serverInfo obj;
        obj.serverId  = serverNumber;
        obj.threadId = newThread [globalThreadIndex];
        obj.queue.push_back (newThread [globalThreadIndex]);
        serverInfoVector.push_back (obj);

        // Now, since something has been pushed in the vector, it makes sense to wake up the sleeping thread.

        // Now, since something has been pushed in the vector, it makes sense to wake up the sleeping thread.
        pthread_cond_signal (&demoConditionVar);

        pthread_mutex_unlock(&demoMutex);

        pthread_join (newThread [globalThreadIndex], NULL);
    }
    else
    {
        pthread_mutex_unlock(&demoMutex);
    }
}


int main ()
{
    fp = fopen ("xyz", "w");
    pthread_mutex_init (&demoMutex, NULL);
    pthread_cond_init (&demoConditionVar, NULL);

    checkServerExists (1, "anisha");
    globalThreadIndex++;
    checkServerExists (2, "anisha");

    return 0;
}
0 голосов
/ 16 февраля 2012

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...