본문 바로가기

C Language

mutex null 속성으로 초기화 + fork

`pthread_mutex_init(program.write_lock, NULL);`에서 `NULL`을 할당하는 것은 뮤텍스를 초기화할 때 **기본 속성**을 사용하겠다는 의미입니다. `pthread_mutex_init` 함수는 뮤텍스를 초기화하는 데 사용되며, 두 번째 매개변수로 뮤텍스의 속성을 지정할 수 있습니다. 이 매개변수에 `NULL`을 전달하면 뮤텍스는 기본 속성으로 초기화됩니다.

---

### **`pthread_mutex_init` 함수의 구문**
```c
int pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t *attr);
```

1. **`mutex`**:
   - 초기화할 뮤텍스의 포인터입니다.

2. **`attr`**:
   - 뮤텍스의 속성을 지정하는 `pthread_mutexattr_t` 구조체의 포인터입니다.
   - `NULL`을 전달하면 뮤텍스는 기본 속성으로 초기화됩니다.

---

### **`NULL`을 할당하는 의미**
- **기본 속성 사용**:
  - `NULL`을 전달하면 뮤텍스는 기본 속성으로 초기화됩니다.
  - 기본 속성은 일반적으로 다음과 같은 특징을 가집니다:
    - **비재진입(non-recursive)**: 같은 스레드가 뮤텍스를 중복으로 잠글 수 없습니다.
    - **프로세스 간 공유 불가**: 뮤텍스는 같은 프로세스 내의 스레드들만 공유할 수 있습니다.

- **간단한 사용**:
  - 특별한 속성이 필요하지 않은 경우 `NULL`을 사용하여 뮤텍스를 초기화하면 코드가 간결해집니다.
  - 대부분의 경우 기본 속성으로 충분합니다.

---

### **뮤텍스 속성 커스터마이징**
만약 뮤텍스에 특별한 속성을 부여하고 싶다면 `pthread_mutexattr_t` 구조체를 사용하여 속성을 설정할 수 있습니다. 예를 들어:
1. **재진입 가능한 뮤텍스(recursive mutex)**:
   - 같은 스레드가 뮤텍스를 중복으로 잠글 수 있습니다.
   - `pthread_mutexattr_settype` 함수를 사용하여 설정합니다.

2. **프로세스 간 공유 가능한 뮤텍스**:
   - 뮤텍스를 다른 프로세스와 공유할 수 있습니다.
   - `pthread_mutexattr_setpshared` 함수를 사용하여 설정합니다.

---

### **예시: 기본 속성으로 뮤텍스 초기화**
```c
pthread_mutex_t mutex;
pthread_mutex_init(&mutex, NULL); // 기본 속성으로 뮤텍스 초기화
```

---

### **예시: 커스터마이징된 속성으로 뮤텍스 초기화**
```c
pthread_mutex_t mutex;
pthread_mutexattr_t attr;

// 뮤텍스 속성 초기화
pthread_mutexattr_init(&attr);

// 재진입 가능한 뮤텍스로 설정
pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);

// 뮤텍스 초기화 (커스터마이징된 속성 사용)
pthread_mutex_init(&mutex, &attr);

// 뮤텍스 속성 해제
pthread_mutexattr_destroy(&attr);
```

---

### **결론**
- `pthread_mutex_init(program.write_lock, NULL);`에서 `NULL`은 뮤텍스를 기본 속성으로 초기화하겠다는 의미입니다.
- 기본 속성은 일반적인 경우에 충분하며, 특별한 속성이 필요한 경우 `pthread_mutexattr_t`를 사용하여 커스터마이징할 수 있습니다.
- `NULL`을 사용하면 코드가 간결해지고, 대부분의 경우 기본 속성으로 충분하므로 널리 사용됩니다.

 

`init_philos` 함수는 철학자 문제(Dining Philosophers Problem)에서 각 철학자(`t_philo`)의 상태와 속성을 초기화하는 역할을 합니다. 이 함수는 철학자의 ID, 식사 상태, 포크(뮤텍스) 할당, 공유 자원(뮤텍스 및 플래그) 설정 등을 수행합니다. 아래에서 이 함수를 상세히 설명하겠습니다.

---

### **함수의 매개변수**
1. **`t_philo *philos`**:
   - 철학자들의 정보를 저장할 배열입니다. 각 철학자는 `t_philo` 구조체로 표현됩니다.

2. **`t_program *program`**:
   - 프로그램 전체의 상태와 공유 자원을 관리하는 구조체입니다. 여기서는 뮤텍스와 플래그를 공유합니다.

3. **`pthread_mutex_t *forks`**:
   - 철학자들이 사용할 포크(뮤텍스) 배열입니다. 각 포크는 철학자들이 공유하는 자원입니다.

4. **`char **argv`**:
   - 프로그램 실행 시 전달된 인자들입니다. 철학자의 수, 시간 설정 등을 포함합니다.

---

### **함수의 동작**
1. **철학자 배열 초기화**:
   - `while` 루프를 사용하여 철학자 배열(`philos`)을 초기화합니다.
   - 각 철학자의 ID, 식사 상태, 식사 횟수, 시작 시간, 마지막 식사 시간 등을 설정합니다.

2. **입력 값 초기화**:
   - `init_input` 함수를 호출하여 철학자의 시간 설정(`time_to_die`, `time_to_eat`, `time_to_sleep`)을 초기화합니다.

3. **공유 자원 설정**:
   - 철학자가 공유하는 뮤텍스와 플래그를 설정합니다.
     - `write_lock`: 출력 동기화를 위한 뮤텍스.
     - `dead_lock`: 철학자의 죽음 상태를 보호하는 뮤텍스.
     - `meal_lock`: 철학자의 식사 상태를 보호하는 뮤텍스.
     - `dead`: 철학자의 죽음 상태를 나타내는 플래그.

4. **포크 할당**:
   - 각 철학자에게 왼쪽 포크와 오른쪽 포크를 할당합니다.
   - 첫 번째 철학자의 오른쪽 포크는 마지막 철학자의 포크와 동일합니다 (원형 테이블 구조).

---

### **코드 상세 설명**
```c
void init_philos(t_philo *philos, t_program *program, pthread_mutex_t *forks, char **argv)
{
    int i;

    i = 0;
    while (i < ft_atoi(argv[1])) // 철학자의 수만큼 반복
    {
        // 철학자의 기본 정보 설정
        philos[i].id = i + 1; // 철학자의 ID (1부터 시작)
        philos[i].eating = 0; // 철학자의 식사 상태 (0: 먹지 않음)
        philos[i].meals_eaten = 0; // 철학자가 먹은 식사 횟수 (초기값 0)
        init_input(&philos[i], argv); // 철학자의 시간 설정 초기화

        // 시간 관련 정보 설정
        philos[i].start_time = get_current_time(); // 프로그램 시작 시간
        philos[i].last_meal = get_current_time(); // 마지막 식사 시간 (초기값은 현재 시간)

        // 공유 자원 설정
        philos[i].write_lock = &program->write_lock; // 출력용 뮤텍스
        philos[i].dead_lock = &program->dead_lock; // 죽음 상태 보호용 뮤텍스
        philos[i].meal_lock = &program->meal_lock; // 식사 상태 보호용 뮤텍스
        philos[i].dead = &program->dead_flag; // 철학자의 죽음 상태 플래그

        // 포크 할당
        philos[i].l_fork = &forks[i]; // 왼쪽 포크
        if (i == 0)
            philos[i].r_fork = &forks[philos[i].num_of_philos - 1]; // 첫 번째 철학자의 오른쪽 포크는 마지막 철학자의 포크
        else
            philos[i].r_fork = &forks[i - 1]; // 나머지 철학자의 오른쪽 포크

        i++;
    }
}
```

---

### **초기화 과정의 주요 포인트**
1. **철학자의 ID**:
   - 철학자의 ID는 1부터 시작합니다. 이는 출력 시 철학자를 구분하는 데 사용됩니다.

2. **시간 설정**:
   - `init_input` 함수는 `argv`를 기반으로 철학자의 `time_to_die`, `time_to_eat`, `time_to_sleep` 등을 설정합니다.

3. **공유 자원**:
   - 모든 철학자는 `program` 구조체의 뮤텍스와 플래그를 공유합니다. 이를 통해 철학자 간의 동기화가 이루어집니다.

4. **포크 할당**:
   - 철학자들은 원형 테이블에 앉아 있으므로, 첫 번째 철학자의 오른쪽 포크는 마지막 철학자의 포크와 동일합니다.

---

### **예시: 철학자 5명 초기화**
1. **입력**:
   - `argv[1] = "5"` (철학자 수)
   - `argv[2] = "800"` (time_to_die)
   - `argv[3] = "200"` (time_to_eat)
   - `argv[4] = "200"` (time_to_sleep)

2. **초기화 결과**:
   - 철학자 1: 왼쪽 포크 = `forks[0]`, 오른쪽 포크 = `forks[4]`
   - 철학자 2: 왼쪽 포크 = `forks[1]`, 오른쪽 포크 = `forks[0]`
   - 철학자 3: 왼쪽 포크 = `forks[2]`, 오른쪽 포크 = `forks[1]`
   - 철학자 4: 왼쪽 포크 = `forks[3]`, 오른쪽 포크 = `forks[2]`
   - 철학자 5: 왼쪽 포크 = `forks[4]`, 오른쪽 포크 = `forks[3]`

---

### **결론**
- `init_philos` 함수는 철학자 문제에서 각 철학자의 상태와 속성을 초기화합니다.
- 철학자의 ID, 시간 설정, 공유 자원, 포크 할당 등을 설정하여 철학자 문제를 해결할 준비를 합니다.
- 이 함수는 철학자 문제의 핵심 로직을 구현하기 위한 기반을 제공합니다.

'C Language' 카테고리의 다른 글

pthread_create pthread_join 설명  (0) 2025.03.12
pthread_mutex_lock unlock  (0) 2025.03.10
mutex  (0) 2025.03.10
cpp 01  (0) 2025.03.10
minishell01  (0) 2025.03.08