PosixThread Signal 예제

개요

  1. Overrun에 대한 주의가 필요 (Signal을 여러번 발생시킨만큼 전부 sigwait으로 받을수 있다는 보장이 안되기 때문에 이에 대한 처리가 세심하게 필요)
  2. pthread_sigmask를 통해서 적절한 SIG_BLOCK과 SIG_UNBLOCK을 처리해주도록 하여 제어해야 함.

예제소스

  • 예제 소스
    /*
    Copyright (C) MINZKN.COM
    All rights reserved.
    Code by JaeHyuk Cho <mailto:minzkn@minzkn.com>
    */
    
    #if !defined(_ISOC99_SOURCE)
    # define _ISOC99_SOURCE (1L)
    #endif
    
    #if !defined(_GNU_SOURCE)
    # define _GNU_SOURCE (1L)
    #endif
    
    #include <sys/types.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <signal.h>
    #include <unistd.h>
    
    #include <pthread.h>
    
    #define def_thread_signal_test_case (1) /* 0=control by main, 1=control by thread */
    #define def_thread_signal_interval (1000) /* msec */
    
    typedef struct thread_context_ts {
        pthread_mutex_t m_lock;
        int m_overrun_count;
    }__thread_context_t;
    #define thread_context_t __thread_context_t
    
    typedef void *(*th_t)(void *);
    
    static void *thread_common(void *s_argument, const char *s_caller_name, size_t s_caller_line);
    
    static void *thread1(void *s_argument);
    static void *thread2(void *s_argument);
    static void *thread3(void *s_argument);
    static void *thread4(void *s_argument);
    
    static void thread5_signal_handler(int s_signal);
    static void *thread5_use_signal(void *s_argument);
    
    int main(int s_argc, char **s_argv);
    
    #if def_thread_signal_test_case == (1)
    typedef struct thread_control_info_ts {
        th_t *m_thread_table;
        int m_thread_count;
        pthread_t *m_thread_id;
        thread_context_t *m_thread_context;
    }__thread_control_info_t;
    #define thread_control_info_t __thread_control_info_t
    
    static void *control_thread(void *s_argument);
    
    static void *control_thread(void *s_argument)
    {
        thread_control_info_t *s_control = (thread_control_info_t *)s_argument;
    
        int s_thread_index;
        int s_tick, s_count;
    
        (void)fprintf(stdout, "control thread begin\n");
    
        do {
            sigset_t s_sigmask;
    
            /* int sigemptyset(sigset_t *set); */
            (void)sigemptyset((sigset_t *)(&s_sigmask));
    
            /* int sigaddset(sigset_t *set, int signum); */
            (void)sigaddset((sigset_t *)(&s_sigmask), SIGINT);
            (void)sigaddset((sigset_t *)(&s_sigmask), SIGUSR1);
            (void)sigaddset((sigset_t *)(&s_sigmask), SIGUSR2);
    
            /* int pthread_sigmask(int how, const sigset_t *set, sigset_t *oldset) */
            (void)pthread_sigmask(SIG_BLOCK, (const sigset_t *)(&s_sigmask), (sigset_t *)0);
        }while(0);
    
        for(s_tick = 0;;s_tick++) {
            s_thread_index = s_tick % s_control->m_thread_count;
    
            (void)fprintf(stdout, "---- tick=%d, thread_index=%d\n", s_tick, s_thread_index);
    
            for(s_count = 0;s_count < (s_thread_index + 1);s_count++) {
                /* int pthread_mutex_lock(pthread_mutex_t *mutex) */
                (void)pthread_mutex_lock((pthread_mutex_t *)(&s_control->m_thread_context[s_thread_index].m_lock));
                ++s_control->m_thread_context[s_thread_index].m_overrun_count;
    
                /* int pthread_kill(pthread_t thread, int sig); */
                (void)pthread_kill(s_control->m_thread_id[s_thread_index], SIGINT);
    
                /* int pthread_unmutex_lock(pthread_mutex_t *mutex) */
                (void)pthread_mutex_unlock((pthread_mutex_t *)(&s_control->m_thread_context[s_thread_index].m_lock));
    #if 0L
                (void)fprintf(stdout, "pthread_kill[%d] done.\n", s_thread_index);
    #endif
            }
    
    #if def_thread_signal_interval > (0)
            usleep(def_thread_signal_interval * 1000);
    #endif
        }
    
        (void)fprintf(stdout, "control thread end\n");
    
        return((void *)0);
    }
    #endif
    
    static void *thread_common(void *s_argument, const char *s_caller_name, size_t s_caller_line)
    {
        thread_context_t *s_thread_context = (thread_context_t *)s_argument;
        int s_overrun_index, s_overrun_count;
    
        sigset_t s_sigmask;
        int s_signal;
    
        int s_count;
    
        /* int sigemptyset(sigset_t *set); */
        (void)sigemptyset((sigset_t *)(&s_sigmask));
    
        /* int sigaddset(sigset_t *set, int signum); */
        (void)sigaddset((sigset_t *)(&s_sigmask), SIGINT);
        (void)sigaddset((sigset_t *)(&s_sigmask), SIGUSR1);
        (void)sigaddset((sigset_t *)(&s_sigmask), SIGUSR2);
    
        /* int pthread_sigmask(int how, const sigset_t *set, sigset_t *oldset) */
        (void)pthread_sigmask(SIG_BLOCK, (const sigset_t *)(&s_sigmask), (sigset_t *)0);
    
        for(s_count = 0;;) {
            /* int sigwait(const sigset_t *set, int *sig); */
            (void)sigwait((const sigset_t *)(&s_sigmask), (int *)(&s_signal));
    
            /* int pthread_mutex_lock(pthread_mutex_t *mutex) */
            (void)pthread_mutex_lock((pthread_mutex_t *)(&s_thread_context->m_lock));
            s_overrun_count = s_thread_context->m_overrun_count;
            s_thread_context->m_overrun_count -= s_overrun_count;
            /* int pthread_mutex_unlock(pthread_mutex_t *mutex) */
            (void)pthread_mutex_unlock((pthread_mutex_t *)(&s_thread_context->m_lock));
    
            for(s_overrun_index = 0;s_overrun_index < s_overrun_count;s_overrun_index++) {
                (void)fprintf(stdout, "\t[%d/%d]: \x1b[1;33m%s\x1b[0m:%lu[%d] sig=%d\n", s_overrun_index + 1, s_overrun_count, s_caller_name, (unsigned long)s_caller_line, s_count, s_signal);
            }
            ++s_count;
        }
    
        return((void *)0);
    }
    
    static void *thread1(void *s_argument)
    {
        return(thread_common(s_argument, __func__, __LINE__));
    }
    
    static void *thread2(void *s_argument)
    {
        return(thread_common(s_argument, __func__, __LINE__));
    }
    
    static void *thread3(void *s_argument)
    {
        return(thread_common(s_argument, __func__, __LINE__));
    }
    
    static void *thread4(void *s_argument)
    {
        return(thread_common(s_argument, __func__, __LINE__));
    }
    
    static void thread5_signal_handler(int s_signal)
    {
        (void)fprintf(stderr, "\t*** func=\"%s\", signal=%d\n", __func__, s_signal);
    }
    
    static void *thread5_use_signal(void *s_argument)
    {
        thread_context_t *s_thread_context = (thread_context_t *)s_argument;
        int s_overrun_index, s_overrun_count;
    
        sigset_t s_sigmask;
        struct sigaction s_sigaction;
    
        int s_count;
    
        /* int sigemptyset(sigset_t *set); */
        (void)sigemptyset((sigset_t *)(&s_sigmask));
    
        /* int sigaddset(sigset_t *set, int signum); */
        (void)sigaddset((sigset_t *)(&s_sigmask), SIGINT);
        (void)sigaddset((sigset_t *)(&s_sigmask), SIGUSR1);
        (void)sigaddset((sigset_t *)(&s_sigmask), SIGUSR2);
    
        /* int sigaction(int signum, const struct sigaction *act, struct sigaction *oldact); */
        (void)memset((void *)(&s_sigaction), 0, sizeof(s_sigaction));
        s_sigaction.sa_handler = &thread5_signal_handler;
        (void)sigaction(SIGINT, (const struct sigaction *)(&s_sigaction), (struct sigaction *)0);
        (void)sigaction(SIGUSR1, (const struct sigaction *)(&s_sigaction), (struct sigaction *)0);
        (void)sigaction(SIGUSR2, (const struct sigaction *)(&s_sigaction), (struct sigaction *)0);
    
        /* int pthread_sigmask(int how, const sigset_t *set, sigset_t *oldset) */
        (void)pthread_sigmask(SIG_UNBLOCK, (const sigset_t *)(&s_sigmask), (sigset_t *)0);
    
        for(s_count = 0;;) {
            /* int pthread_mutex_lock(pthread_mutex_t *mutex) */
            (void)pthread_mutex_lock((pthread_mutex_t *)(&s_thread_context->m_lock));
            s_overrun_count = s_thread_context->m_overrun_count;
            s_thread_context->m_overrun_count -= s_overrun_count;
            /* int pthread_mutex_unlock(pthread_mutex_t *mutex) */
            (void)pthread_mutex_unlock((pthread_mutex_t *)(&s_thread_context->m_lock));
    
            if(s_overrun_count <= 0) {
                usleep(10 * 1000); /* load balance */
                continue;
            }
    
            for(s_overrun_index = 0;s_overrun_index < s_overrun_count;s_overrun_index++) {
                (void)fprintf(stdout, "\t[%d/%d]: \x1b[1;33m%s\x1b[0m:%lu[%d]\n", s_overrun_index + 1, s_overrun_count, __func__, (unsigned long)__LINE__, s_count);
            }
            ++s_count;
        }
    
        return((void *)0);
    }
    
    int main(int s_argc, char **s_argv)
    {
        th_t s_thread_table[] = {
            &thread1,
            &thread2,
            &thread3,
            &thread4,
            &thread5_use_signal,
            (th_t)0
        };
        int s_thread_index, s_thread_count;
    
        pthread_t s_thread_id[sizeof(s_thread_table) / sizeof(void *)];
        thread_context_t s_thread_context[sizeof(s_thread_table) / sizeof(void *)];
    
    #if def_thread_signal_test_case == (0)
        (void)fprintf(stdout, "thread signal test begin. [Quit to Ctrl+\\]\n");
    #elif def_thread_signal_test_case == (1)
        (void)fprintf(stdout, "thread signal test begin. [Quit to Ctrl+C]\n");
    #endif
    
    #if def_thread_signal_test_case == (0)
        do {
            sigset_t s_sigmask;
    
            /* int sigemptyset(sigset_t *set); */
            (void)sigemptyset((sigset_t *)(&s_sigmask));
    
            /* int sigaddset(sigset_t *set, int signum); */
            (void)sigaddset((sigset_t *)(&s_sigmask), SIGINT);
            (void)sigaddset((sigset_t *)(&s_sigmask), SIGUSR1);
            (void)sigaddset((sigset_t *)(&s_sigmask), SIGUSR2);
    
            /* int pthread_sigmask(int how, const sigset_t *set, sigset_t *oldset) */
            (void)pthread_sigmask(SIG_BLOCK, (const sigset_t *)(&s_sigmask), (sigset_t *)0);
        }while(0);
    #endif
    
        for(s_thread_index = 0;s_thread_table[s_thread_index] != ((th_t)0);s_thread_index++) {
            /* int pthread_mutex_init(pthread_mutex_t *restrict mutex, const pthread_mutexattr_t *restrict attr); */
            (void)pthread_mutex_init((pthread_mutex_t *)(&s_thread_context[s_thread_index].m_lock), (const pthread_mutexattr_t *)0);
            s_thread_context[s_thread_index].m_overrun_count = 0;
    
            /* int pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine) (void *), void *arg); */
            if(pthread_create((pthread_t *)(&s_thread_id[s_thread_index]), (const pthread_attr_t *)0, s_thread_table[s_thread_index], (void *)(&s_thread_context[s_thread_index])) == 0) {
                (void)pthread_detach(s_thread_id[s_thread_index]);
    
                (void)fprintf(stdout, "pthread_create[%d] done.\n", s_thread_index);
            }
        }
        s_thread_count = s_thread_index;
    
    #if def_thread_signal_test_case == (0)
        do {
            int s_tick, s_count;
    
            for(s_tick = 0;;s_tick++) {
                s_thread_index = s_tick % s_thread_count;
    
                (void)fprintf(stdout, "---- tick=%d, thread_index=%d\n", s_tick, s_thread_index);
    
                for(s_count = 0;s_count < (s_thread_index + 1);s_count++) {
                    /* int pthread_mutex_lock(pthread_mutex_t *mutex) */
                    (void)pthread_mutex_lock((pthread_mutex_t *)(&s_thread_context[s_thread_index].m_lock));
                    ++s_thread_context[s_thread_index].m_overrun_count;
    
                    /* int pthread_kill(pthread_t thread, int sig); */
                    (void)pthread_kill(s_thread_id[s_thread_index], SIGINT);
    
                    /* int pthread_unmutex_lock(pthread_mutex_t *mutex) */
                    (void)pthread_mutex_unlock((pthread_mutex_t *)(&s_thread_context[s_thread_index].m_lock));
    
    #if 0L
                    (void)fprintf(stdout, "pthread_kill[%d] done.\n", s_thread_index);
    #endif
                }
    
    #if def_thread_signal_interval > (0)
                usleep(def_thread_signal_interval * 1000);
    #endif
            }
        }while(0);
    #elif def_thread_signal_test_case == (1)
        do {
            thread_control_info_t s_control_local;
            thread_control_info_t *s_control;
    
            pthread_t s_control_thread_id;
    
            s_control = (thread_control_info_t *)memset((void *)(&s_control_local), 0, sizeof(s_control_local));
    
            s_control->m_thread_table = (th_t *)(&s_thread_table[0]);
            s_control->m_thread_count = s_thread_count;
            s_control->m_thread_id = (pthread_t *)(&s_thread_id[0]);
            s_control->m_thread_context = (thread_context_t *)(&s_thread_context[0]);
    
            if(pthread_create((pthread_t *)(&s_control_thread_id), (const pthread_attr_t *)0, control_thread, (void *)s_control) == 0) {
                (void)fprintf(stdout, "control thread join...\n");
                /* int pthread_join(pthread_t thread, void **retval); */
                (void)pthread_join(s_control_thread_id, (void **)0);
            }
    
        }while(0);
    #endif
    
        (void)fprintf(stdout, "thread signal test end.\n");
    
        return(EXIT_SUCCESS);
    }
    
    /* vim: set expandtab: */
    /* End of source */
    



/*
[ FrontPage | PrintView | RawView | RSS ]

Copyright ⓒ MINZKN.COM
All Rights Reserved.

MINZKN
*/