GlueThread Library

jy·2025년 2월 5일

Gluethread란?

  • gluethread는 포괄적인 데이터 구조로, 다양한 데이터 구조(ex: linkedlist, queue, tree 등) 위에 쉽게 붙일 수 있는(glue) 방식이다.
  • Linux 커널에서 사용되는 list_head 구조와 유사하다.(Intrusive Linked List)
  • thread라는 이름이 붙었지만, MultiThread 프로그래밍과는 무관. 단지 노드 간의 연결을 비유적으로 표현한 것.

Gluethread 특징

  • 가볍고 효율적이다.
  • 이미 존재하는 구조체에 쉽게 통합 가능하다.
  • 특정 데이터 구조에 얽매이지 않고, 다목적으로 사용 가능하다.

glthread_t

typedef struct _glthread{

    struct _glthread *left;
    struct _glthread *right;
} glthread_t;

주요 함수 기능

  1. void glthread_add_next(glthread_t base_glthread, glthread_t new_glthread);
    -> base_glthread노드 기준으로 옆에 리스트 추가
  2. void glthread_add_before(glthread_t curr_glthread, glthread_t new_glthread)
    -> base_glthread노드 기준으로 이전에 리스트 추가
  3. void remove_glthread(glthread_t *curr_glthread)
    -> glthread 리스트에서 노드 삭제
  4. void glthread_priority_insert(glthread_t base_glthread,
    glthread_t
    glthread,
    int (comp_fn)(void , void *),
    int offset);
    -> comp_fn 함수 포인터로 값을 비교하여 glthread 노드를 리스트에 추가

매크로 분석

#define GLTHREAD_TO_STRUCT(fn_name, structure_name, field_name)                        \
    static inline structure_name * fn_name(glthread_t *glthreadptr){                   \
        return (structure_name *)((char *)(glthreadptr) - (char *)&(((structure_name *)0)->field_name)); \
    }

매크로 인자
1. fn_name
- 함수 이름을 정의. 이 함수는 glthread_t 포인터에서 전체 구조체로의 변환을 수행
2. structure_name
- 변환 대상이 되는 구조체의 이름
3. filed_name
- 구조체 내부의 glthread_t 필드 이름. 이 필드는 구조체와 연결된 특정 노드 역할을 수행.

동작 원리
1. (struct_name *)0

  • 구조체의 포인터의 주소가 0이면 구조체(struct_name)의 시작점인 주솟값을 얻을 수 있다.
  1. ((char)&(((struct_name )0)->field_name)
  • struct_name 타입의 포인터가 0일때, 해당 필드(field_name)의 수조를 계산하여 필드의 offset을 얻을 수 있다.
  1. 계산: (char*)(glthreadptr) - (char*)&(((struct_name *)0)->field_name)
  • glthreadptr 을 char* 포인팅하여 1byte 단위로 계산 가능하게 함.
  • glthreadptr 포인터에서 해당 필드의 오프셋을 빼서 구조체의 시작 주소를 계산

사용예제

#include "glthread.h"
#include <memory.h>
#include <stdlib.h>
#include <stdio.h>

typedef struct _person{

    int age;
    int weight;
    glthread_t glthread;
} person_t ;

int 
senior_citizen(person_t *p1, person_t *p2){

    if(p1->age == p2->age) return 0;
    if(p1->age < p2->age) return 1;
    return -1;
}

#define offset(struct_name, fld_name) \
    (unsigned int)&(((struct_name *)0)->fld_name)

GLTHREAD_TO_STRUCT(thread_to_person, person_t, glthread);

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

    person_t person[5];
    memset(person, 0, sizeof(person_t) * 5);
    person[0].age = 1;
    person[0].weight = 2;
    person[1].age = 3;
    person[1].weight = 4;
    person[2].age = 5;
    person[2].weight = 6;
    person[3].age = 7;
    person[3].weight = 8;
    person[4].age = 9;
    person[4].weight = 10;

    glthread_t base_glthread;
    init_glthread(&base_glthread);

    glthread_priority_insert(&base_glthread, &person[4].glthread, senior_citizen, offset(person_t, glthread));
    glthread_priority_insert(&base_glthread, &person[3].glthread, senior_citizen, offset(person_t, glthread));
    glthread_priority_insert(&base_glthread, &person[2].glthread, senior_citizen, offset(person_t, glthread));
    glthread_priority_insert(&base_glthread, &person[1].glthread, senior_citizen, offset(person_t, glthread));
    glthread_priority_insert(&base_glthread, &person[0].glthread, senior_citizen, offset(person_t, glthread));

    glthread_t *curr = NULL;
    ITERATE_GLTHREAD_BEGIN(&base_glthread, curr){

        person_t *p = thread_to_person(curr);
        printf("Age = %d\n", p->age);
    } ITERATE_GLTHREAD_END(&base_glthread, curr);
    
    return 0;
}

git 주소 : https://github.com/JuneYul/TcpIp_stack/tree/main/gluethread

0개의 댓글