#keywords posix,thread,threads,쓰레드,unix #title PosixThread Signal 예제 [wiki:Home 대문] / [wiki:CategoryProgramming 프로그래밍] / [wiki:PosixThreadSignalExample PosixThread Signal 예제] ---- == [wiki:PosixThreadSignalExample PosixThread Signal 예제] == * 작성자 조재혁([mailto:minzkn@minzkn.com]) * 고친과정 2011년 2월 24일 : 처음씀 [[TableOfContents]] === 개요 === 1. Overrun에 대한 주의가 필요 (Signal을 여러번 발생시킨만큼 전부 sigwait으로 받을수 있다는 보장이 안되기 때문에 이에 대한 처리가 세심하게 필요) 1. pthread_sigmask를 통해서 적절한 SIG_BLOCK과 SIG_UNBLOCK을 처리해주도록 하여 제어해야 함. === 예제소스 === * 예제 소스 {{{#!enscript c /* Copyright (C) MINZKN.COM All rights reserved. Code by JaeHyuk Cho */ #if !defined(_ISOC99_SOURCE) # define _ISOC99_SOURCE (1L) #endif #if !defined(_GNU_SOURCE) # define _GNU_SOURCE (1L) #endif #include #include #include #include #include #include #include #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 */ }}}