【问题标题】:Why pthread_cond_signal could hang up?为什么 pthread_cond_signal 会挂断?
【发布时间】:2022-08-16 10:42:12
【问题描述】:

我已经阅读了一些建议的主题,但不幸的是还没有找到我的问题的答案。 任何建议都非常感谢。

所以,我正在做这个巨大的项目,这里是影响代码 sn-p:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <time.h>
#include <sys/time.h>
#include <unistd.h>
#include <pthread.h>

static pthread_mutex_t mutex;
static pthread_cond_t cond;

static char *timestamp()
{
    time_t rawtime;
    struct tm *timeinfo;
    char *stamp;

    time(&rawtime);
    timeinfo = localtime(&rawtime);
    stamp = asctime(timeinfo);
    stamp[strlen(stamp) - 1] = \'\\0\';

    return stamp;
}

static void *monitor(void *ctx)
{
    int ret;
    struct timeval now;
    struct timespec timeout = { 0 };

    while (1)
    {
        gettimeofday(&now, NULL);

        timeout.tv_sec = now.tv_sec + 1;

        pthread_mutex_lock(&mutex);

        if (!(ret = pthread_cond_timedwait(&cond, &mutex, &timeout)))
        {
            printf(\"%s [%s] Signaled successfully!\\n\", timestamp(),
                __FUNCTION__);

        }
        else if (ret == ETIMEDOUT)
            printf(\"%s [%s] Timed out!\\n\", timestamp(), __FUNCTION__);

        pthread_mutex_unlock(&mutex);
    }
    return NULL;
}

int main()
{
    pthread_t tid;

    if (pthread_mutex_init(&mutex, NULL) < 0)
    {
        perror(\"mutex\");
        return -1;
    }

    if (pthread_cond_init(&cond, NULL) < 0)
    {
        perror(\"cond\");
        pthread_mutex_destroy(&mutex);
        return -1;
    }

    if (pthread_create(&tid, NULL, monitor, NULL) < 0)
    {
        perror(\"create()\");
        pthread_cond_destroy(&cond);
        pthread_mutex_destroy(&mutex);
        return -1;
    }

    pthread_detach(tid);
    srand(time(NULL));

    while (1)
    {
        int delay = rand() % 5 + 1;

        printf(\"%s [main] Waker is sleeping for %d sec\\n\", timestamp(), delay);
        sleep(delay);

        printf(\"%s [main] Signaling...\\n\", timestamp());
        pthread_mutex_lock(&mutex);
        printf(\"%s [main] Lock aquired...\\n\", timestamp());
        pthread_cond_signal(&cond);
        printf(\"%s [main] Signaled. Releasing...\\n\", timestamp());
        pthread_mutex_unlock(&mutex);
    }

    pthread_cond_destroy(&cond);
    pthread_mutex_destroy(&mutex);

    return 0;
}

每次当[main] 线程伸出pthread_cond_signalpthread_cond_timedwait 正在等待(未超时)时,就会发生卡住。

pthread_cond_signal 之前锁定互斥锁是最佳实践,我已阅读here

This 主题说,如果 cond/mutex 在等待之前被破坏,则可能会发生这种卡住。

This主题描述虚假的醒来,这可能会导致这种卡住。

但是,两者似乎都与我的情况无关。 我还假设这种行为可能与ulimit -s/-i 有关。但是设置为unlimited 值并没有帮助。 有趣的是[monitor] 线程也像[main] 一样卡住了。

UPD

    Program output:
    Wed Jun  8 13:34:10 2022 [main] Waker is sleeping for 4 sec
    Wed Jun  8 13:34:10 2022 [monitor] Timed out!
    Wed Jun  8 13:34:11 2022 [monitor] Timed out!
    Wed Jun  8 13:34:12 2022 [monitor] Timed out!
    Wed Jun  8 13:34:13 2022 [monitor] Timed out!
    Wed Jun  8 13:34:14 2022 [main] Signaling...
    Wed Jun  8 13:34:14 2022 [main] Lock acquired...
    /*No prints at all */

UPD2:

我重构了上面的例子只是为了像这样使用pthread_cond_wait

[monitor thread]
pthread_mutex_lock(&mutex);
pthread_cond_wait(&cond, &mutex);
pthread_mutex_unlock(&mutex);

[main thread]
pthread_mutex_lock(&mutex);
pthread_cond_signal(&cond);
pthread_mutex_unlock(&mutex);

我又挂在pthread_cond_signal上... 因此,从操作系统的角度来看,这似乎是个问题。我只知道小 ulimit 的堆栈大小可能会导致堆栈溢出,这可能会导致这种卡住(依赖于拱门的东西,在我的情况下 100% 可重现)。 有谁知道其他可能会影响它的特定配置?

  • 我不确定这是否是您的问题,但 asctime 不是线程安全的。它返回一个指向两个线程同时读写的静态缓冲区的指针。您应该改用asctime_rstrftime
  • 还有另一个竞争错误:您的监视器线程在每次循环迭代时解锁并锁定互斥锁,除了它的等待。在这两者之间,主线程可以锁定互斥体并发出条件信号。由于监视器当时没有等待条件,因此它会错过信号,并且后续的等待将永远不会收到它。
  • 现在解锁/锁定竞赛并不能解释你的挂起,因为即使监视器错过了一个信号,主线程也会在几秒钟内发送另一个信号。但这是一个设计问题。通常监视器的主循环应该不是有一个明确的解锁/锁定:在任何时候它都应该等待或持有互斥锁。如果它确实解锁了互斥锁,那么在它再次等待之前,它需要确定(通过检查一些其他程序状态)是否已经发生了所需的事件。
  • \“如果当前没有线程阻塞在 cond 上,则 pthread_cond_broadcast() 和 pthread_cond_signal() 函数将无效。\”由于手册页:linux.die.net/man/3/pthread_cond_signal
  • 正确的。就像我说的,它没有解释为什么pthread_cond_signal 应该看起来挂起。在这个程序中,唯一的后果是监视器会错过信号并等待比预期更长的时间,但在实际程序中(没有超时)它可能会死锁。我无法重现您描述的挂起,所以我只能猜测。

标签: c linux multithreading pthreads embedded-linux


【解决方案1】:

找到原因了吗,我也遇到了同样的情况。

【讨论】:

    猜你喜欢
    • 2016-02-23
    • 2015-03-09
    • 1970-01-01
    • 2022-09-29
    • 2018-03-27
    • 1970-01-01
    • 2021-06-09
    • 2012-02-17
    • 1970-01-01
    相关资源
    最近更新 更多