h1. Using Thread Pool Library

h3. 라이브러리 정보
  * 라이브러리 위치: libvos/include/threadpool/*
  * 라이브러리 파일: threadpool.h threadpool_queue.h threadpool.c threadpool_queue.c
  * include는 "threadpool.h"만 하면 됨


h3. threadpool.h - 구조체
{code:java|title=thpool}
/* threadpool에 필요한 모든 정보를 포함하는 구조체 */
typedef struct threadpool_all {
        unsigned int worker_num;
        unsigned int max_queue_size;
        unsigned int curr_queue_size;
        struct threadpool_work *work_queue_head;
        struct threadpool_work *work_queue_tail;
        pthread_t *threads;
        pthread_mutex_t work_lock;
        pthread_cond_t work_pool_available;
        pthread_cond_t work_pool_exist;
        pthread_cond_t work_empty;
        int working;
} thpool;
{code}

* 설명
threadpool에 필요한 정보들을 구조체 형식으로 묶어두었다.
worker_num과 max_queue_size는 각각 생성할 스레드 풀의 개수와 작업을 할당할 work pool의 최대 사이즈이다.
curr_queue_size는 현재 work_pool에 할당된 작업의 개수를 나타낸다.
work_queue_head, work_queue_tail은 work pool을 위한 queue의 head와 tail을 나타낸다.
threads는 pthread_create() 함수에 의해 생성된 스레드의 ID값이 저장된다.
work_lock은 스레드 풀의 작업 수행 함수에서 전역적으로 사용되는 데이터들에 대한 mutex lock을 위해 선언되었다.
work_pool_available은 work pool에 할당할 수 있는 작업 공간이 있다는 것에 대한 신호를 보내기 위해 선언되었다.
work_pool_exist는 작업이 할당된 뒤, 작업 수행 함수에게 현재 할당된 작업이 있다는 신호를 보내기 위해 선언되었다.


h3. threadpool.h - 함수

{code:java|title=threadpool_init(), 스레드 풀 초기화 함수}
int threadpool_init( thpool **init_pool, unsigned int worker_num, unsigned int max_queue );
{code}

* threadpool의 초기화를 위한 함수이다.
* 첫 번째 인자인 init_pool은 thpool 구조체 변수가 전달되며, 해당 변수에 대한 별도의 작업은 필요하지 않다.
* 두 번째 인자인 worker_num은 thread pool을 위한 스레드의 개수가 전달된다.
* 세 번째 인자인 max_queue는 work queue의 크기를 나타낸다.



{code:java|title=threadpool_worker(), queue에 할당된 작업을 실행하는 threadpool worker 함수}
void *threadpool_worker( void *arg );
{code}

* queue에 할당된 작업을 수행하기 위한 함수로, 라이브러리 내부에서 실행되기 때문에 사용자는 고려할 필요가 없다.



{code:java|title=threadpool_add_work(), 스레드 풀에 작업을 추가하는 함수}
int threadpool_add_work( thpool *th_pool, void *(*worker)(void *), void *worker_arg );
{code}

* thread pool에 작업을 할당하는 함수이다.
* 첫 번째 인자인 th_pool에는 이전에 초기화 함수를 통하여 전달되었던 첫 번째 변수가 그대로 전달된다.
* 두 번째 인자인 worker은 실제 스레드가 수행할 함수가 전달된다.
* 세 번째 인자인 worker_arg는 그에 대한(스레드 함수) 인자가 전달된다.


{code:java|title=threadpool_adjust(), 스레드 풀 갯수를 재조정하는 함수}
int threadpool_adjust( thpool **adj_pool, unsigned int worker_num, unsigned int max_queue );
{code}

* 중간에 thread pool 및 work pool의 크기를 조절하기 위한 함수로써, 현재는 threadpool의 destroy&init를 wrapping하는것으로 대체되었다.
* 첫 번째 인인 adj_pool은 이전에 초기화 함수를 통하여 전달되었던 첫 번째 변수가 그대로 전달된다.
* 두 번째와 세 번째 인자인 worker_num과 max_queue는 각각 thread pool의 크기, work pool의 크기이다.



{code:java|title=threadpool_destroy(), 스레드 풀 소멸 함수}
int threadpool_destroy( thpool *thp );
{code}

* thread pool의 종료 시 소멸 과정을 수행하는 함수이다.
* 인자인 thp에는 이전에 초기화 함수를 통하여 전달되었던 첫 번째 변수가 그대로 전달된다.


{code:java|title=work_queue_none()}
static int __inline__ work_queue_none( thpool *thp )
{
        return (thp->curr_queue_size == 0);
}
{code}

* 현재 work pool이 비어있는지 체크하는 함수
* thread pool 라이브러리 내부에서 호출되므로 사용자는 해당 함수를 고려할 필요가 없다.

{code:java|title=work_queue_full()}
static int __inline__ work_queue_full( thpool *thp )
{
        return (thp->curr_queue_size == thp->max_queue_size);
}
{code}

* 현재 work pool이 최대치인지 체크하는 함수
* thread pool 라이브러리 내부에서 호출되므로 사용자는 해당 함수를 고려할 필요가 없다.

{code:java|title=thp_error_handling()}
/* 에러 핸들링 함수, 에러 처리는 모두 해당 함수로 했기 때문에,
 * 차후 함수를 수정하여 콘솔 출력 등으로 바꿔 사용 할 수 있음. */
static void __inline__ thp_error_handling( char *str )
{
        char err_msg[512];

        snprintf( err_msg, sizeof(err_msg) -1, "threadpool> %s", str );
        perror(err_msg);
}
{code}

* thread pool 내부에서 사용되는 error handling 전용 함수이다.
* 에러 처리를 위한 루틴은 따로 wrapping해 두었으며, 수정하여 사용이 가능하다.
* thread pool 라이브러리 내부에서 호출되므로 사용자는 해당 함수를 고려할 필요가 없다.



h3. threadpool_queue.h - 구조체
{code:java|title=thpwork}
/* queue 형태로 되어있는 work 구조체 */
typedef struct threadpool_work {
        void *(*worker_func)(void *);
        void *worker_arg;
        struct threadpool_work *prev;
        struct threadpool_work *next;
} thpwork;
{code}

* 설명
스레드가 수행할 작업을 work queue 형태로 할당하기 위해 만들어진 구조체로,
worker_func와 worker_arg는 각각 수행할 스레드 함수와 그에 대한 인자를 나타낸다.
prev, next는 owrker queue의 전/후를 가리키는 linked list이다.

h3. threadpool_queue.h - 함수

{code:java|title=queue_init()}
void queue_init( thpwork **head, thpwork **tail );
{code}

* work pool을 위한 queue를 초기화하는 함수이다.
* thread pool 라이브러리 내부에서 호출되므로 사용자는 해당 함수를 고려할 필요가 없다.

{code:java|title=queue_push()}
void queue_push( thpwork *v, thpwork *head, thpwork *tail );
{code}

* work pool에 작업을 할당하기 위한 queue의 push 함수이다.
* thread pool 라이브러리 내부에서 호출되므로 사용자는 해당 함수를 고려할 필요가 없다.


{code:java|title=queue_pop()}
thpwork *queue_pop( thpwork *head, thpwork *tail );
{code}

* work pool에 할당된 작업을 수행하기 위해 가져오는 queue의 pop 함수이다.
* thread pool 라이브러리 내부에서 호출되므로 사용자는 해당 함수를 고려할 필요가 없다.

{code:java|title=queue_destroy()}
void queue_destroy( thpwork *head, thpwork *tail );
{code}

* work pool의 소멸과정을 수행하는 queue의 destroy 함수이다.
* thread pool 라이브러리 내부에서 호출되므로 사용자는 해당 함수를 고려할 필요가 없다.

h3. 사용 예 - Pseudo Code
* 해당 라이브러리를 사용하면 몇 번의 함수 호출로 스레드 풀을 간단히 적용할 수 있다.
{code}
void *thrd_func( int *client_sock );

int main( void )
{
      thpool *th_pool; // 스레드 풀에 사용되는 변수

      ...

      threadpool_init( &th_pool, 7, 64 ); // 스레드 풀에 사용되는 초기화 함수

      while(1)
      {
            cli_sfd = accept(..);

            threadpool_add_work( th_pool, (void *)thrd_func, &cli_sfd ); // 스레드 풀에 사용되는 작업 추가 함수

            if( somecheck ) {
                  threadpool_adjust( &th_pool, 5, 32 ); // 스레드 풀에 사용되는 풀 정보 조절 함수
            }
      }
      threadpool_destroy( th_pool ); // 스레드 풀에 사용되는 소멸 함수

      return 0;
}
{code}