【问题标题】:How to set pthread_cond_signal so that the program doesn't hang?如何设置 pthread_cond_signal 使程序不挂起?
【发布时间】:2012-02-16 09:22:54
【问题描述】:

编辑 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 并被条件变量阻塞。

checkServerExists 函数然后将值输入到全局结构的队列中,设置线程唤醒的信号。

现在,我错过了什么?

编辑 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:

【问题讨论】:

  • 创建一个我们自己可以使用和测试的自包含测试用例比提供一些代码 sn-ps 更有用。例如,found 是什么?
  • @PlasmaHH 抱歉,我在这里删除了一些代码,发现是其中之一:让我展示整个代码 - 它不是太大。
  • 顺便说一句。我建议您在编译器中启用警告并修复它们。在 gcc 中使用 -Wextra -Wall 我至少收到 7 个我认为您应该关心的警告,其中一个可能是罪魁祸首(我没有被初始化)
  • 这里有一个非常简单的规则:永远不要调用pthread_cond_wait,除非你已经安排好了其他线程会向条件变量发出信号。如果您正在调用pthread_cond_wait,则应该等待您知道另一个线程将要执行的某些特定操作,之后它将向条件变量发出信号。 (另外,您应该在while 循环中调用pthread_cond_waitwait。您可能会醒来但仍需要等待。)

标签: c++ multithreading pthreads


【解决方案1】:

此代码已损坏。

首先,您正在修改checkServerExists 中的变量,而不锁定互斥锁。这是未定义的行为。

如果你解决了这个问题,那么你也不会在printHello 函数之外发出你的条件变量信号。因此,一旦线程在pthread_cond_wait 调用中阻塞,它只会由于虚假唤醒而唤醒,并且当另一个printHello 线程向它发出信号时。您应该在设置condition 标志的位置调用pthread_cond_signal,而不是在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;
}

【讨论】:

  • 我知道,无耻的垃圾邮件,但在我的回答中,这说明了:stackoverflow.com/a/5538447/104774。我希望这会有所帮助。
  • Anthony,我已经编辑了代码 - 它比以前的要好,但仍然挂起。请看一看。
  • 您的第二段不正确。在 pthread_cond_signal 上查找 man 或 docs。
  • @MaximYegorushkin: condition 是原始代码中的一个变量,Anisha 已将其删除。
  • pastebin.com/Hvdvv7XU 我做了各种修改,但代码还是不干净。但它不再挂起。
【解决方案2】:

我猜第二个线程没有从它的等待中唤醒。第一个线程尝试向条件变量发出信号,但秒数甚至还没有开始。我想知道为什么它甚至超过了第一个线程中的等待,但它可能永远不会等待,因为线程在条件已经为 1 之后开始执行。

【讨论】:

    猜你喜欢
    • 2016-02-23
    • 2022-08-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-05-18
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多