[t:/]$ 지식_

쓰레드 수 제한하며 노는 쓰레드 없게 하기

2018/11/21

복잡한 락 안 쓰고 쓰레드 풀 가동하기. 보통 연산중심의 프로그램에서는 멀티쓰레드를 과하게 쓰면 CPU 풀로 쓰면서 시스템이 맛탱이 간다. IO 한다고 놀 시간이 없다. 컨테이너 기반에서는 아마도 상세한 쿼타 제한이 있겠지만 보통은 대충 쓰면 다른 세입자나 프로세스에 민폐끼친다.

그래서 쓰레드 수 제한을 걸어야 하는디, 그냥 join으로 기다리면 노는 쓰레드가 생긴다. 1번 쓰레드가 빨리 끝나고 2번 쓰레드가 주구장창 일하고 있는 경우가 그렇다. 방법은 detach인데, 그러면 이제부터 락 문제가 생기는데 대개 귀찮다. 컨디셔널 변수에 뮤텍스 얹고 시그널 뿌리고 아오 귀찮아. 다른 사람들이 어떻게 쉽게 푸는지 잘 모르겠다. 내가 본 코드들은 거의 뮤텍스에 동기화를 쌈싸먹고 있어서 코드를 보는 순간 지지를 선언하게 된다.

나는 간단하게는 다음과 같이 한다. 가끔 아토믹 확장으로 수제-_-스핀락을 쓰기도 한다. usleep이 거슬리지만 대개는 join으로 기다리는 것 보다는 문제 없다. 대부분의 삽질 시간을 쓰레드 컨텍스트에서 소모하고 있기 때문이다. usleep(0)을 쓰면 컨텍스트를 전환하며 cpu 입장에서는 숨통이 트인다. 안 쓰면 cpu 하나는 쌩으로 뺑이친다. 즉 아래 예제에서 usleep(0)이라도 넣지 않으면 cpu 사용률은 500%를 친다. 넣으면 401% 정도로 쇼부본다.

중간에 보이는 __sync 함수는 아토믹 확장 함수 중에 하나다. 아마도 앞뒤에 asm 으로 간단한 경량 스핀락과 메모리 배리어가 들어있겠지만 자세히는 안 봤다. 여튼 대충 동작하는데 문제 없는 것 같다.

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>

int th_pool;
#define TH_POOL_MAX 4

void *go(void *arg)
{

    int *p = (int *)arg;
    int i;

    pthread_detach(pthread_self());

    for (i = 0; i < 100000; i++) {

        (*p)++;
    }
    __sync_fetch_and_sub(&th_pool, 1);
    pthread_exit((void *) 0);

}

int main(int argc, char *argv[])
{

    int i;
    pthread_t th[100];
    int count[100];
    int t;

    for (i = 0; i < 100; i++) {
        count[i] = 0;

        pthread_create(&th[i], NULL, &go, &count[i]);
        __sync_fetch_and_add(&th_pool, 1);

        while(th_pool == TH_POOL_MAX) {
            usleep(1000);
        }

    }

    while(th_pool > 0) {
        usleep(10000);
    }

    t = 0;
    for (i = 0; i < 100; i++) {

        t += count[i];

    }

    printf("t = %d\n", t);

    return 0;

}








[t:/] is not "technology - root". dawnsea, rss