【问题标题】:Timer freezes after some time计时器在一段时间后冻结
【发布时间】:2016-02-22 14:35:39
【问题描述】:

我正在运行以下实现计时器的程序。当线程从前一个运行线程接收到条件变量信号后唤醒时,它会创建一个计时器并在计时器到期时向下一个线程发送信号。我希望它运行一段时间,但运行一些时间后计时器停止计时。

//Import 
#define _POSIX_C_SOURCE 199309
#include <sched.h>
#include <unistd.h>
#include <sys/wait.h>
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <unistd.h>
#include <time.h>
#include <sys/time.h>
#include <signal.h>
#include <errno.h>
#define NUM_THREADS 10

#define CLOCKID CLOCK_REALTIME
#define SIG SIGUSR1
timer_t timerid;

pthread_cond_t   condA[NUM_THREADS+1]  = PTHREAD_COND_INITIALIZER;
pthread_mutex_t  mutex  = PTHREAD_MUTEX_INITIALIZER;

pthread_t tid[NUM_THREADS];
int state = 0;

static void handler(int sig, siginfo_t *si, void *uc)
{
    if(si->si_value.sival_ptr != &timerid){
        printf("Stray signal\n");
    } else {
        //printf("Caught signal %d from timer\n", sig);
    }

        pthread_cond_signal(&condA[state]);
}

void *threadA(void *data_)
{
    int i = 0, s;
    long int loopNum, j;

    int turn = (intptr_t)data_;

    struct timeval tval_result;

    // Timer's part starts

    struct sigevent sev;
    struct itimerspec its;
    long long freq_nanosecs;
    sigset_t mask;
    struct sigaction sa;
    // TImer'spart ends

    while(1)
    {

        /* Wait for state A */
        pthread_mutex_lock(&mutex);

        for (;state != turn;)
        {
            s = pthread_cond_wait(&condA[turn], &mutex);
            if (s != 0)
                perror("pthread_cond_wait");
           // printf("main(): state = %d\n", state);
        }
        pthread_mutex_unlock(&mutex);

        //do stuff
        for(j=0;j<10000;j++)
            {//some dummy time consuming works}

        sa.sa_flags = SA_SIGINFO;
        sa.sa_sigaction = handler;
        sigemptyset(&sa.sa_mask);
        sigaction(SIG, &sa, NULL);

        sev.sigev_notify = SIGEV_SIGNAL;
        sev.sigev_signo = SIG;
        sev.sigev_value.sival_ptr = &timerid;
        timer_create(CLOCKID, &sev, &timerid);
        /* Start the timer */

        its.it_value.tv_sec = 0;
        its.it_value.tv_nsec = 2000;
        its.it_interval.tv_sec = 0;
        its.it_interval.tv_nsec = 0;

        timer_settime(timerid, 0, &its, NULL);
        pthread_mutex_lock(&mutex);
        state = (state +1)%NUM_THREADS;
        //pthread_cond_signal(&condA[state]);
        pthread_mutex_unlock(&mutex);
        // Timer's code ends
    }

}

int main(int argc, char *argv[])
{
    int data = 0;
    int err;

    while(data < NUM_THREADS)
    {
        //create our threads
        err = pthread_create(&tid[data], NULL, threadA, (void *)(intptr_t)data);
        if(err != 0)
            printf("\ncan't create thread :[%s]", strerror(err));
        else
           // printf("\n Thread created successfully\n");

        data++;
    }

    pthread_exit(NULL);
}

虽然没有执行 printf 语句,但为什么一段时间后它会冻结? 如果不。的计时器是有限的,我应该使用什么其他策略来解决这个问题?

【问题讨论】:

  • 这些定时器实例,'timer_delete'在哪里调用?
  • 没用过,不知道在哪里调用?我尝试在 threadA() 函数的开头调用 timer_delete(),并使用最后一个计时器的 timerid,但我遇到了段错误。如果你能建议我正确的地方,你会很高兴的。
  • 你不能只重复使用一个计时器吗?在 while(1) 之前创建它并重新使用它?
  • 是的,这可能是一个解决方案,但我的要求是:每个线程将工作 15 微秒,然后它应该进入阻塞状态。下一个线程应该在 1 微秒后唤醒。从而在每次执行线程之间产生 1 微秒的延迟。如果我将间隔设置为 1 微秒,它只会工作一次,并在每 1 微秒后继续滴答作响。这不是我想要的。
  • 我认为您可以使用单独的线程(例如计时器线程)在特定时间间隔后唤醒其他线程。

标签: c multithreading timer posix posix-api


【解决方案1】:

POSIX 说:

在异步调用的信号处理程序中使用 pthread_cond_signal() 函数是不安全的。

您很可能最终破坏了pthread_cond_wait/pthread_cond_signal 的状态,并且任何事情都可能发生。

不要混合使用线程和信号处理程序,这只会导致疯狂。在信号处理程序中允许您做的事情很少,与线程相关的事情更少,很难确保正确的线程最终处理正确的信号,等等。

如果您无论如何都在做线程,则在一个线程中实现一个计时器,该计时器计算它需要休眠多少时间才能传递下一个事件(不要将它硬编码到您的计时器周期,因为这会使您的计时器漂移),睡这么多,然后打电话给pthread_cond_signal

此外,赤裸裸的pthread_cond_signal 调用是一种糟糕的形式,而且通常是一个错误。你可能会很不幸,在另一个线程执行pthread_cond_wait 之前调用它,你的信号会丢失。正常的做法是设置一个变量(受互斥体保护,这就是pthread_cond_signal 想要互斥体的原因),然后发出设置变量的信号。

如果您认为这工作量太大,在这种情况下,条件变量可能不是正确的机制,您应该改用信号量。顺便说一句,根据 POSIX 从信号处理程序调用 sem_post 是合法的,但我仍然认为将线程与信号混合是一个坏主意。

【讨论】:

  • 感谢您如此彻底的回复。看起来很有希望。我也会实现 sem_post 并回到这个答案。我也想看看别人的看法。
猜你喜欢
  • 1970-01-01
  • 2021-05-26
  • 2021-03-13
  • 1970-01-01
  • 2020-11-11
  • 2015-11-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多