반응형

스레드에서 clock함수 사용 시 발생하는 문제


스레드를 여러개 만들고 각 스레드에 시간 함수인 clock을 사용하면 시간이 이상 출력될 수 있다. 예를 들어 pthread를 이용하여 만든 스레드가 두 개일 경우 시간이 두배로 흘러가고 세 개일 경우 세배로 흘러간다.

이는 clock함수가 프로세스 클록 횟수를 이용하여 시간을 얻어오는데, 스레드끼리 클록 횟수를 공유하여 스레드가 호출될 떄마다 프로세스 클록이 증가하는 것으로 보인다. 

 

 

clock 대신 clock_gettime 사용


clock 대신 clock_gettime함수를 사용하여 위 문제를 해결할 수 있다. clock_gettime함수는 CLOCK_REALTIME과 CLOCK_MONOTINIC 방식 중 선택하여 시간을 얻어올 수 있는데, CLOCK_REALTIME은 시스템 시간을 얻어오므로 시스템 시간이 변경되면 수행 시간이 변경되는 문제가 있다. 따라서 특정 시점으로부터 흐르는 시간을 호출하는 CLOCK_MONOTONIC 방식을 사용한다.

 

 

예제 코드


 

 

clock을 사용한 코드

스레드A와 B가 약 0.5초에 한 번씩 호출된다.

#include <pthread.h>
#include <stdio.h>
#include <stdint.h>
#include <time.h>

void *threadA()
{
    clock_t timeBegin, timeEnd;
    uint8_t intTime = 0;
    double currentTime = 0;
    timeBegin = clock();
    while(1)
    {
        timeEnd = clock();
        currentTime = (double)(timeEnd-timeBegin)/CLOCKS_PER_SEC;
        if(currentTime > intTime)
        {
            intTime++;
            printf("thread A %f\n", currentTime);
        }
    }
}

void *threadB()
{
    clock_t timeBeginB, timeEndB;
    uint8_t intTime = 0;
    double currentTime = 0;
    timeBeginB = clock();
    while(1)
    {
        timeEndB = clock();
        currentTime = (double)(timeEndB-timeBeginB)/CLOCKS_PER_SEC;
        if(currentTime > intTime)
        {
            intTime++;
            printf("thread B %f\n", currentTime);
        }
    }
}

int main()
{
    printf("hello world\n");

    pthread_t tA, tB;
    uint8_t threadReturn = 0;
    threadReturn = pthread_create(&tA, NULL, threadA, NULL);
    if(threadReturn != 0)
    {
        printf("thread A create fail : %d\n", threadReturn);
    }
    threadReturn = pthread_create(&tB, NULL, threadB, NULL);
    if(threadReturn != 0)
    {
        printf("thread B create fail : %d\n", threadReturn);
    }

    threadReturn = pthread_join(tA, NULL);
    if(threadReturn != 0)
    {
        printf("thread A join fail\n");
    }
    threadReturn = pthread_join(tB, NULL);
    if(threadReturn != 0)
    {
        printf("thread B join fail\n");
    }
    return 0;
}

 

clock_gettime을 사용한 코드

스레드 A와 B가 약 1초에 한 번씩 호출된다.

#include <pthread.h>
#include <stdio.h>
#include <stdint.h>
#include <time.h>

void *threadA()
{
    struct timespec timeBegin, timeEnd;
    uint8_t intTime = 0;
    double currentTime = 0;
    clock_gettime(CLOCK_MONOTONIC, &timeBegin);
    while(1)
    {
        clock_gettime(CLOCK_MONOTONIC, &timeEnd);
        currentTime = timeEnd.tv_sec - timeBegin.tv_sec;
        if(currentTime > intTime)
        {
            intTime++;
            printf("thread A %f\n", currentTime);
        }
    }
}

void *threadB()
{
    struct timespec timeBegin, timeEnd;
    uint8_t intTime = 0;
    double currentTime = 0;
    clock_gettime(CLOCK_MONOTONIC, &timeBegin);
    while(1)
    {
        clock_gettime(CLOCK_MONOTONIC, &timeEnd);
        currentTime = timeEnd.tv_sec - timeBegin.tv_sec;
        if(currentTime > intTime)
        {
            intTime++;
            printf("thread B %f\n", currentTime);
        }
    }
}


int main()
{
    printf("hello world\n");

    pthread_t tA, tB;
    uint8_t threadReturn = 0;
    threadReturn = pthread_create(&tA, NULL, threadA, NULL);
    if(threadReturn != 0)
    {
        printf("thread A create fail : %d\n", threadReturn);
    }
    threadReturn = pthread_create(&tB, NULL, threadB, NULL);
    if(threadReturn != 0)
    {
        printf("thread B create fail : %d\n", threadReturn);
    }

    threadReturn = pthread_join(tA, NULL);
    if(threadReturn != 0)
    {
        printf("thread A join fail\n");
    }
    threadReturn = pthread_join(tB, NULL);
    if(threadReturn != 0)
    {
        printf("thread B join fail\n");
    }
    return 0;
}