/** * \file cf_thread.c * * \author myusgun * * \brief 멀티 스레드 구현 */ #include "cf_thread.h" #include "cf_local.h" #include "cf_error.h" #include #if defined(_WIN32) || defined(_WIN64) # include # include # define THREAD_TYPE HANDLE # define THREAD_RETURN unsigned long /**< 스레드 워커 함수 반환 형 */ # define THREAD_CALL __stdcall #else // #if defined(_WIN32) || defined(_WIN64) # include # define THREAD_TYPE pthread_t # define THREAD_RETURN void * /**< 스레드 워커 함수 반환 형 */ # define THREAD_CALL #endif // #if defined(_WIN32) || defined(_WIN64) #define ASSERT_CTX(__ctx) \ if (__ctx == NULL) \ return CF_ERROR_THREAD_INVALID_CTX typedef THREAD_RETURN (THREAD_CALL * THREAD_WORKER) (void *); typedef struct __cf_thread_ctx__ { THREAD_TYPE tid; THREAD_WORKER callback; void * arg; } CF_THREAD_CONTEXT; /** * 스레드 컨텍스트를 생성 * * \return 성공 시, CF_OK; 실패 시, 오류 코드 * * \param ctx 스레드 컨텍스트 주소 * \param callback 스레드 워커 함수 이름 * \param arg 스레드 함수로 전달할 인자 */ int CF_Thread_Create (cf_ctx * ctx, CF_Thread_Function callback, void * arg) { CF_THREAD_CONTEXT * context = NULL; context = NEWCTX (CF_THREAD_CONTEXT); if (context == NULL) return CF_ERROR_THREAD_CREATE_CTX; context->callback = (THREAD_WORKER) callback; context->arg = arg; *ctx = (cf_ctx) context; return CF_OK; } /** * 스레드를 실행 * * \return 성공 시, CF_OK; 실패 시, 오류 코드 * * \param ctx 스레드 컨텍스트 * * \remarks * pthread에서 지원되는 스케줄링 정책은 SCHED_OTHER, SCHED_FIFO, SCHED_RR 등이 존재
* 일반적으로 설정되는 스케줄링 정책의 기본값은 SCHED_OTHER이며, * 솔라리스 환경에서 SCHED_OTHER는 TS(timesharing) 방식으로 명시되어 있음
* 그러나 개발 단계에서 테스트된 동작은 SCHED_FIFO와 동일하였으며, * 때문에 솔라리스 환경에서는 스케줄링 정책을 SCHED_RR로 명시하도록 함
*
* 참고 url
* - http://kldp.org/node/18841 , "SCHED_OTHER, SCHED_FIFO, SCHED_RR에 대해..."
* - http://blog.naver.com/popjunior/80021646476 , "AIX, CPU 모니터링과 튜닝"
*/ int CF_Thread_Start (cf_ctx ctx) { int result = 0; CF_THREAD_CONTEXT * context = (CF_THREAD_CONTEXT *) ctx; ASSERT_CTX (ctx); #if defined(_WIN32) || defined(_WIN64) context->tid = CreateThread (NULL, 0, context->callback, context->arg, 0, NULL); if (context->tid == NULL) return CF_ERROR_THREAD_START; #else pthread_attr_t * attr = NULL; # if defined(_SOLARIS) pthread_attr_t solarisAttr; struct sched_param sched; attr = &solarisAttr; result = pthread_attr_init (attr); if (result) return CF_ERROR_THREAD_INIT_ATTR; result = pthread_attr_setinheritsched (attr, PTHREAD_EXPLICIT_SCHED); if (result) return CF_ERROR_THREAD_SET_INHERIT_SCHED; result = pthread_attr_setschedpolicy (attr, SCHED_RR); if (result) return CF_ERROR_THREAD_SET_SCHED_POLICY; sched.sched_priority = 1; result = pthread_attr_setschedparam (attr, &sched); if (result) return CF_ERROR_THREAD_SET_SCHED_PARAM; # endif // # if defined(_SOLARIS) result = pthread_create (&context->tid, attr, context->callback, context->arg); if (result) return CF_ERROR_THREAD_START; #endif return result; } /** * 스레드 컨텍스트를 해제 * * \return 성공 시, CF_OK; 실패 시, 오류 코드 * * \param ctx 스레드 컨텍스트 * * \remarks 스레드 컨텍스트를 해제하는 것이며 워커 스레드가 종료되지 않음 */ int CF_Thread_Destroy (cf_ctx ctx) { CF_THREAD_CONTEXT * context = (CF_THREAD_CONTEXT *) ctx; ASSERT_CTX (ctx); #if defined(_WIN32) || defined(_WIN64) if (context->tid == NULL) return CF_ERROR_THREAD_INVALID_ARGS; CloseHandle (context->tid); #endif free (context); return CF_OK; } /** * 스레드가 종료될 때 까지 대기 * * \return CF_OK 반환 * * \param ctx 스레드 컨텍스트 */ int CF_Thread_Join (cf_ctx ctx) { CF_THREAD_CONTEXT * context = (CF_THREAD_CONTEXT *) ctx; char status[16] = {0x00,}; ASSERT_CTX (ctx); #if defined(_WIN32) || defined(_WIN64) WaitForSingleObject (context->tid, INFINITE); #else pthread_join (context->tid, (void **)status); #endif return CF_OK; }