2016-04-27 2 views
3

私のプログラムのメイン機能でPOSIXタイマーを作成しました。メインプログラムの各スレッドは、タイマーを設定しているので、シグナルハンドラは、そのプロセスの次のスレッドを呼び起こす変数を更新します。POSIXタイマーが数回実行された後に電話を切る

タイマーはほとんどの場合よく機能しますが、必ずしもそうではありません。それは時には完全な実行を完了し、他の実行ではハングアップします。考えられる理由は何でしょうか?私の疑惑は信号の配信に関連するものです。ここで

コードです:

#define _GNU_SOURCE 
#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 <signal.h> 
#include <errno.h> 
#include <semaphore.h> 
#include <sys/stat.h> 
#include <fcntl.h> 
#include <syscall.h> 
#define NUM_THREADS 10 

#define CLOCKID CLOCK_REALTIME 
#define SIG SIGUSR1 
int ret; 
timer_t timerid; 
struct sigevent sev; 
struct itimerspec its; 
long long freq_nanosecs; 
sigset_t mask; 
struct sigaction sa; 

sem_t sem[NUM_THREADS]; 
sem_t mute; 

pthread_t tid[NUM_THREADS]; 
int state = 0; 

static void handler(int sig, siginfo_t *si, void *uc) 
{ 
    ret = sem_post(&sem[(state+1)%NUM_THREADS]); 
     if (ret) 
     { 
      printf("Error in Sem Post\n"); 
     } 
     state++; 
} 

void *threadA(void *data_) 
{ 
    int i = 0, s,n,value; 

    long int loopNum; 
    int turn = (intptr_t)data_; 
    struct timespec tval_result,tval_result2; 

    int sid = syscall(SYS_gettid); 
    FILE *fp; 
    fp=fopen("ipc.out","a");  
    fprintf(fp,"thread_%d %d\n",turn,sid); 
    fclose(fp); 

    int counter=0; 

    while(1) 
    { 
     ret = sem_wait(&sem[turn]); 
     if (ret) 
     { 
      printf("Error in Sem Post\n"); 
     } 
     //printf("Thread # -> %d\n",turn); 

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

     ret = timer_settime(timerid, 0, &its, NULL); 
     if (ret < 0) 
      perror("timer_settime"); 

     // Some heavy work 

    counter++; 

    if(counter==100) 
    break; 
    } 
    printf("finished %d\n",turn); 

} 

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

    sa.sa_flags = SA_RESTART; 
    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; 
    ret = timer_create(CLOCKID, &sev, &timerid); 
    if (ret < 0) 
     perror("timer_create"); 

    sem_init(&sem[0], 0, 1); 
    for (i = 1; i < NUM_THREADS; ++i) 
     { 
      sem_init(&sem[i], 0, 0); 
     } 

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

     data++; 
    } 

    pthread_exit(NULL); 
} 

これによると、このプログラムは

finished 0 
finished 1 
finished 2 
finished 3 
finished 4 
finished 5 
finished 6 
finished 7 
finished 8 
finished 9 

にそれはこのように印刷しますが、時間のほとんどは、プログラムがハングアップする時間の一部を印刷する必要があります。

答えて

1

シグナルハンドラに競合状態があります。 sem_postが呼び出されるとすぐに、他のスレッドの1つが実行を開始することができ、そのタイマーは現在のシグナルハンドラが完了する前に起動できます。シグナルハンドラが別のスレッドで再び呼び出される結果になります。その時点でstateは第1のスレッドによってインクリメントされておらず、したがって第2のシグナルハンドラ呼び出しは、間違ったセマフォ上でsem_postを呼び出すことになります。

static void handler(int sig, siginfo_t *si, void *uc) 
{ 
    state++; 
    ret = sem_post(&sem[(state)%NUM_THREADS]); 
    if (ret) 
    { 
     printf("Error in Sem Post\n"); 
    } 
} 

注この解決策はまだ一つの問題が含まれていること:この問題を解決するために

一つの方法は、statesem_postを呼び出す前にインクリメントされていることを確認することです。 printfの呼び出しが正しい順序で行われることを保証するものではありません。

+0

ありがとうございます。あなたが説明したことは意味があります。競争状態を避けるためにプログラムを修正します。上記の変更は、このハングアップの問題を解決するものではありませんが、それは価値があります。 – Scissor

+0

あなたの説明のために@kaylumに感謝します。それは私の問題を解決した。 – Scissor

関連する問題