> For the complete documentation index, see [llms.txt](https://docs.tibero.com/tibero-manuals/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.tibero.com/tibero-manuals/7.2.6.manuals/tbesql-c-guide/multithread-programming.md).

# 멀티 스레드 프로그래밍

tbESQL/C 환경에서 멀티 스레드 프로그램을 작성하는 방법을 설명합니다.

## **개요**

tbESQL/C를 이용하여 멀티 스레&#xB4DC;**(Multi-Thread)** 프로그램을 작성할 수 있습니다. 멀티스레드 프로그램에서는 스레드가 공유하는 리소스에 대해 상호 배&#xC81C;**(Mutual Exclusion)**&#xB97C; 지키기 위한 동기&#xD654;**(Synchronization)** 기법이 중요합니다.

{% hint style="info" %}
**참고**

상호 배제란 여러 개의 스레드가 공통의 리소스에 접근할 때 리소스가 잘못된 조작으로 훼손되는 것을 방지하기 위해, 한 번에 하나의 스레드만 리소스에 접근하도록 제어하는 것을 말합니다.
{% endhint %}

만약 하나의 런타임 컨텍스&#xD2B8;**(Runtime Context)**&#xB97C; 동시에 여러 스레드가 접근할 경우 사용자가 뮤텍&#xC2A4;**(Mutex)** 등을 이용하여 동시 접근을 막아야 합니다.

뮤텍스는 공통의 리소스에 동시에 여러 스레드가 접근하는 것이 아닌, 한 스레드만 접근할 필요가 있을 때 사용합니다. 해당 리소스에 대한 뮤텍스 객체를 생성하고, 뮤텍스 객체가 비신호 상태이면 현재 스레드가 리소스를 사용한 후 이를 반환하고, 뮤텍스 객체가 신호 상태이면, 현재 스레드를 대기 상태로 만듭니다.

tbESQL/C에서는 런타임 컨텍스트를 각 스레드마다 할당해 스레드 간에 상호 배제를 보장할 수 있도록 합니다.

### **런타임 컨텍스트**

tbESQL/C에서는 실행 중인 애플리케이션의 접속 정보와 세션(Session) 정보, 커서 정보 등을 저장하기 위하여 런타임 컨텍스트를 제공합니다.

싱글 스레드(Single-Thread) 기반의 tbESQL/C 프로그램에서는 사용자가 할당하지 않아도 디폴트로 설정된 런타임 컨텍스트가 사용됩니다. 멀티스레드 프로그램의 경우 직접 런타임 컨텍스트를 할당하여 각 스레드마다 자신이 사용할 런타임 컨텍스트를 선택할 수 있고, 스레드 간에 런타임 컨텍스트 정보의 전달이 가능합니다.

사용자는 하나의 런타임 컨텍스트를 공유하는 멀티 스레드 프로그램을 작성할 수 있으나, 이 경우 런타임 컨텍스트에 접근할 때 뮤텍스 등을 이용하여 동시 접근을 막아야 합니다. 그렇게 하지 않으려면 각 스레드마다 런타임 컨텍스트를 할당해 주면 됩니다.

## 프리컴파일러 옵션과 **tbESQL/C** 문장

tbESQL/C에서는 멀티 스레드와 관련하여 프리컴파일러 옵션과 **tbESQL/C** 문장을 제공합니다.

### **프리컴파일러 옵션**

스레드와 관련된 프리컴파일러 옵션에는 THREADS가 있습니다.

멀티스레드 프로그램을 작성하기 위해서는 프리컴파일할 때 THREADS 옵션을 **'YES'**&#xB85C; 설정해야 합니다. 만약 THREADS 옵션을 **'NO'**&#xB85C; 설정하고, 멀티 스레드와 관련된 tbESQL/C 문장을 가진 소스 코드를 프리컴파일할 경우 에러가 발생합니다.

또한 tbESQL/C가 사용하는 tbCLI 라이브러리의 경우 THREADS 옵션을 YES로 설정해야 컨텍스트 관련 문장을 사용할 수 있으며 스레드 사용과 관련된 리소스가 안전한 상태로 라이브러리를 수행합니다.

### **tbESQL/C 문장**

스레드와 관련된 tbESQL/C 문장을 설명하기 전에, **ctx\_var**에 대해 설명하면, ctx\_var는 tbESQL에서 제공하는 **sql\_context** 타입의 호스트 변수입니다. 이 변수는 해당 런타임 컨텍스트를 가리킵니다.

ctx\_var는 다음과 같이 선언합니다.

```
sql_context ctx_var;
```

스레드와 관련된 tbESQL/C 문장은 다음과 같습니다.

#### **ENABLE THREADS**

ENABLE THREADS 문장이 명시된 후부터 실행되는 tbESQL/C 문장은 멀티 스레드 환경에서 실행된다는 것을 의미합니다. 스레드와 관련된 모든 tbESQL/C 문장은 이 문장이 명시된 후에 사용할 수 있습니다.

다음은 ENABLE THREADS 문장을 사용하는 예입니다.

```
EXEC SQL ENABLE THREADS;
```

#### **CONTEXT ALLOCATE**

sql\_context 타입의 ctx\_var 호스트 변수에 런타임 컨텍스트를 할당합니다. 할당된 ctx\_var는 CONTEXT USE, CONTEXT FREE에 사용될 수 있습니다.

다음은 CONTEXT ALLOCATE 문장을 사용하는 예입니다.

```
EXEC SQL CONTEXT ALLOCATE :ctx_var;
```

#### **CONTEXT USE**

EXEC SQL CONTEXT USE 문장을 통해 이 문장 이후의 ESQL 문장에서 사용할 런타임 컨텍스트를 지정해줄 수 있습니다. 이 문장의 적용 범위는 EXEC SQL WHENEVER 문장과 마찬가지로 다음에 나올 EXEC SQL CONTEXT USE 문장 직전까지입니다.

ctx\_var는 EXEC SQL CONTEXT ALLOCATE를 통해 런타임 컨텍스트를 할당 받은 변수이어야 하고, **'DEFAULT'**&#xB85C; 설정할 경우 디폴트로 설정된 런타임 컨텍스트를 사용하겠다는 의미입니다. 모든 tbESQL/C 애플리케이션은 실행될 때 디폴트 런타임 컨텍스트를 할당 받습니다.

다음은 CONTEXT USE 문장을 사용하는 예입니다.

```
EXEC SQL CONTEXT USE { :ctx_var | DEFAULT };
```

#### **CONTEXT FREE**

sql\_context 타입의 ctx\_var 호스트 변수에 할당된 런타임 컨텍스트를 해제합니다. ctx\_var는 EXEC SQL CONTEXT ALLOCATE를 통해 런타임 컨텍스트가 할당된 변수여야 합니다.

다음은 CONTEXT FREE 문장을 사용하는 예입니다.

```
EXEC SQL CONTEXT FREE :ctx_var;
```

## **주의사항**

멀티 스레드 프로그램을 작성할 경우 각각의 스레드가 공유하는 리소스에 대한 상호 배제를 보장하는 것이 중요합니다.

sqlca, sqlda와 같이 전역(global)으로 선언된 변수의 경우 tbESQL/C 런타임 라이브러리(Runtime Library)에서는 상호 배제를 보장하지 않습니다. 그러므로 각 런타임 컨텍스트가 자기만의 변수를 처리할 수 있도록 다음과 같이 프로그램을 작성해야 합니다.

```
sql_context ctx;
...
void do_update()
{
    struct sqlca sqlca;
    /* 지역(local) 변수로 선언하여 현재 스레드(런타임 컨텍스트)만의 변수로 사용합니다. */
...
    EXEC SQL CONTEXT USE :ctx;
    EXEC SQL UPDATE TEST SET COL1 = 'thread' 
             WHERE COL2 = 2.5;
    if (sqlca.sqlcode < 0) do_error();
}
...
```

## **사용 예제**

다음은 스레드 관련된 프리컴파일러 옵션과 tbESQL/C 문장을 사용하는 예입니다.

```
sql_context ctx1; 
sql_context ctx2;

EXEC SQL ENABLE THREADS;
EXEC SQL CONTEXT ALLOCATE :ctx1; 
EXEC SQL CONTEXT ALLOCATE :ctx2;

EXEC SQL INSERT INTO TEST VALUES('test1');
                                /* 디폴트 런타임 컨텍스트에 적용됩니다. */
                                
EXEC SQL CONTEXT USE :ctx1;
EXEC SQL INSERT INTO TEST VALUES('test2');
                                /* ctx1 런타임 컨텍스트에 적용됩니다. */
                                
EXEC SQL CONTEXT USE :ctx2;
EXEC SQL INSERT INTO TEST VALUES('test3');
                                /* ctx2 런타임 컨텍스트에 적용됩니다. */
                                
EXEC SQL COMMIT;
                                /* ctx2 런타임 컨텍스트를 커밋합니다. */
                                
EXEC SQL CONTEXT FREE :ctx1; 
EXEC SQL CONTEXT FREE :ctx2;
```
