일상 메모장

pthread_create 사용법 및 예제 본문

C 언어

pthread_create 사용법 및 예제

핸드오버 2020. 2. 6. 07:20

사용법

-pthread 를 링크해야합니다.

       #include <pthread.h>

       int pthread_create(pthread_t *thread, const pthread_attr_t *attr,
                          void *(*start_routine) (void *), void *arg);

       Compile and link with -pthread.

설명

pthread_create() 함수는 호출되는 프로세스에서 새로운 쓰레드를 시작합니다.

새로운 쓰레드는 argument로 전달된 start_routing(); 함수를 실행합니다.

 

새로운 쓰레드는 아래 조건중 하나에 의하여 종료됩니다.

  • pthread_exit(3), pthread_exit 를 호출하여 리턴값을 지정합니다.
  • start_routing() 함수를 리턴합니다. 이것은 pthread_exit(3)를 호출하는것과 동일합니다.
  • pthread_cancel(3) 함수에 의한 쓰레드 취소
  • 어떠한 쓰레드에서 exit(3)을 호출하거나 main 쓰레드에서 return을 하는경우,
    해당 프로세스의 모든 쓰레드는 종료됩니다.

attr 아규먼트는 쓰레드와 관련된 특성을 지정해주는데 사용됩니다. 이 구조체는 pthread_attr_init(3) 과 

그와 관련된 함수들을 사용하여 초기화됩니다. 만약 attr 이 NULL이면 기본값으로 쓰레드가 생성됩니다.

 

함수가 리턴되기 전에, pthread_create 함수가 정상적으로 호출되면

새로운 쓰레드의 ID를 thread 아규먼트에 저장합니다.

이 값을 사용하여 다른 쓰레드에서 새로운 쓰레드에 후속호출을 하는데 사용할수 있습니다.

 

새로운 쓰레드는 생성한 쓰레드의 signal mask 사본을 그대로 상속받습니다. (pthread_sigmask(3)).

반환 값

pthread_create() 함수가 성공하면, 0을 리턴합니다. 에러가 발생하면 error number를 리턴하고,

thread argument의 포인터가 지정되지 않습니다.

 

에러 값

  • EAGAIN
    • 현재 리소스가 없거나, 최대 쓰레드 개수를 초과한 경우
    • 커널 전체에 최대 프로세스 및 쓰레드 개수를 확인하려면 /proc/sys/kernel/thread-max,
      최대 PID 수를 확인하려면 /proc/sys/kernel/pid-max 를 확인
  • EINVAL
    • attr 아규먼트가 유효하지 않음
  • EPERM
    • Scheduling policy 를 설정할수 있는 권한이 없을경우

참고

X86-32 linux에서 쓰레드의 기본 스택사이즈(stack size)는 2 megabyte입니다.

쓰레드 스택사이즈를 바꾸려면 pthread_attr_setstacksize(3) 함수로 attr 인수에 스택사이즈를 명시적으로 설정할수 있습니다. 현재 시스템의 thread stack size를 확인하려면 'ulimit -s'로 확인할 수 있습니다.

test@VirtualBox:~$ ulimit -s
8192

예제

#include <pthread.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <ctype.h>

#define handle_error_en(en, msg) \
        do { errno = en; perror(msg); exit(EXIT_FAILURE); } while (0)

#define handle_error(msg) \
        do { perror(msg); exit(EXIT_FAILURE); } while (0)

struct thread_info {    /* Used as argument to thread_start() */
    pthread_t thread_id;        /* ID returned by pthread_create() */
    int       thread_num;       /* Application-defined thread # */
    char     *argv_string;      /* From command-line argument */
};

/* 쓰레드 시작 함수: 쓰레드 스택의 top 부분 근처의 주소를 출력하고,
   argv_string의 사본 대문자를 반환합니다. */

static void *
thread_start(void *arg)
{
    struct thread_info *tinfo = arg;
    char *uargv, *p;

    printf("Thread %d: top of stack near %p; argv_string=%s\n",
            tinfo->thread_num, &p, tinfo->argv_string);

    uargv = strdup(tinfo->argv_string);
    if (uargv == NULL)
        handle_error("strdup");
		
    for (p = uargv; *p != '\0'; p++)
        *p = toupper(*p);

    return uargv;
}

int
main(int argc, char *argv[])
{
    int s, tnum, opt, num_threads;
    struct thread_info *tinfo;
    pthread_attr_t attr;
    int stack_size;
    void *res;

    /* "-s" 옵션은 프로그램 쓰레드의 스택사이즈를 설정함 */

    stack_size = -1;
    while ((opt = getopt(argc, argv, "s:")) != -1) {
        switch (opt) {
        case 's':
            stack_size = strtoul(optarg, NULL, 0);
            break;

        default:
            fprintf(stderr, "Usage: %s [-s stack-size] arg...\n",
                    argv[0]);
            exit(EXIT_FAILURE);
        }
    }

    num_threads = argc - optind;

    /* 쓰레드 attr 을 초기화 */

    s = pthread_attr_init(&attr);
    if (s != 0)
        handle_error_en(s, "pthread_attr_init");

    if (stack_size > 0) {
        s = pthread_attr_setstacksize(&attr, stack_size);
        if (s != 0)
            handle_error_en(s, "pthread_attr_setstacksize");
    }

    /* pthread_create() 의 argument의 메모리 할당 */

    tinfo = calloc(num_threads, sizeof(struct thread_info));
    if (tinfo == NULL)
        handle_error("calloc");

    /* 각 쓰레드를 생성함 */

    for (tnum = 0; tnum < num_threads; tnum++) {
        tinfo[tnum].thread_num = tnum + 1;
        tinfo[tnum].argv_string = argv[optind + tnum];

        /* tinfo[] 안에 thread ID를 저장합니다. */

        s = pthread_create(&tinfo[tnum].thread_id, &attr,
                           &thread_start, &tinfo[tnum]);
        if (s != 0)
            handle_error_en(s, "pthread_create");
    }

    /* 더이상 사용할 필요없는 쓰레드 attributes 오브젝트를 삭제합니다. */

    s = pthread_attr_destroy(&attr);
    if (s != 0)
        handle_error_en(s, "pthread_attr_destroy");

    /* 각 쓰레드를 join 하고, 쓰레드의 리턴값을 출력합니다. */

    for (tnum = 0; tnum < num_threads; tnum++) {
        s = pthread_join(tinfo[tnum].thread_id, &res);
        if (s != 0)
            handle_error_en(s, "pthread_join");

        printf("Joined with thread %d; returned value was %s\n",
                tinfo[tnum].thread_num, (char *) res);
        free(res);      /* 쓰레드에서 생성한 메모리를 해제합니다. */
    }

    free(tinfo);
    exit(EXIT_SUCCESS);
}