반응형

루아에서의 스레드(Thread)를 설명 드리겠습니다.

이글은 스레드에 대한 개념이 있으셔야 이해하실 수 있습니다. 앞서 설명드린 스레드에 대하여를 우선 읽어 보시기 바랍니다.

 

루아의 코드는 루아 가상머신이 돌려줍니다. 즉 루아 가상 머신이 스레드를 돌려줘야 합니다.

엄밀히 말하면 C/C++ 로 만든 스레드와는 다릅니다. C/C++ 로 만든 프로그램은 CPU 가 직접(OS 가 직접) 실행하는 코드이지요. 그러나 루아의 코드는 루아 가상머신이 중간에서 돌려주는 역할을 하기때문에, 실질적인 C/C++ 의 스레드를 생각하시면 약간의 오류를 범하실 수 있습니다.

단, 루아의 스레드 역시 하나의 가상머신(이것도 하나의 머신이니까요)에서 돌아주는 스레드 역할을 한다는 것이죠.

루아에서는 스레드를 Coroutine 이라고 합니다.

 

루아의 coroutine은 간단하게 이렇습니다.

 

  1. 루아의 스레드는 함수에서 출발한다.
  2. 루아의 스레드는 함수단위로 만들수 있다.
  3. 루아의 스레드는 coroutine 에 의하여 관리된다.
  4. 루아의 스레드는 c/c++ 에 의하여 만들어지는 스레드와는 다르지만 그 역할을 갖다.

정도로 요약할 수 있습니다.

 

루아원문에 보면

What are coroutines?

 

Coroutines allow us to execute several tasks at once. This is done in a controlled manner by passing control to each routine and waiting until the routine says it has finished. We can reenter the routine to continue at a later time and by doing this repeatedly we achieve multi-tasking.

이라고 나와 있습니다. 즉 한번에 여러가지의 일을 실행할 수 있도록 해주는 것이며, 이러한 루틴들이 서로 실행하며, 또는 대기하면서 기다리며 , 하는 동작을 하게 됩니다.

 

스레드의 생성

루아에서는 스레드를 다음과 같이 생성 합니다.

co = coroutine.create(함수명)

 

즉, 어떠한 함수를 스레드 함수로 만들 수 있습니다. return 되는 값은 thread 인식자라 생각하시면 됩니다.

function foo()
 print("foo",1)
end


co = coroutine.create(foo)

print(co)

위의 코드를 돌려보면

thread: 0137C300

와 같이 결과가 나옵니다. 물론 숫자는 인식자로 각각 다르게 나올 것 입니다.

 

위의 코드는 foo() 라는 함수를 coroutine.create 에 의하여 하나의 스레드함수로 만든 것이고 그 식별자를 co 라는 변수에 담아 놓은 것 입니다.

 

하나의 스레드는 그 상태가 있습니다. 즉 스레드가 어떤 상태이냐 즉, 살아 있나, 죽었나, 돌고 있나, 잠시 멈추어 있나 등의 상태를 가집니다.

 

생성된 스레드의 상태를 알아보는 함수는

coroutine.status(스레드인식자)

 

입니다.

function foo()
 print("foo",1)
end


co = coroutine.create(foo)

print(coroutine.status(co))

 

결과

suspended

위와 같이 coroutine.status() 함수에 의하여 스레드 함수의 상태를 알아 볼 수 있습니다.

스레드 함수는 생성 당시에는 "suspended" 라는 상태에 있습니다. 즉 멈추어 있는 상태 입니다.

 

스레드 함수를 실행하는 방법은

coroutine.resume(스레드인식자)

 

입니다.

function foo()
 print("foo",1)
end


co = coroutine.create(foo)

coroutine.resume(co)

 

결과

foo 1

 

위와 같은 코드로 생성된 thread 함수를 호출하는 것 입니다. 그냥 foo() 라고 함수를 호출하면 스레드로 호출되는 것이 아닙니다.

반드시 coroutine.resume() 로 해당 함수의 스레드 식별자를 이용하여 호출해 주어야 합니다.

위의 결과는 그냥 foo() 함수를 호출하는 것과 별 차이가 없습니다.

 

function foo()
 print("foo",1)

 -- 무엇인가 여기서 다른일을 하고 싶어요
 print("foo",2)
end

foo()

 

결과

foo 1
foo 2

위의 함수를 생각해보죠. foo() 함수가 호출되면 print 함수에 의하여 foo 1 이라는 결과가 나오고 바로 다음의 print 함수에 의하여 foo 2 라는 결과가 나오겠죠. 당연한 결과 입니다.

우리의 목적은 foo 함수가 호출될때 첫번째 print 를 수행하고, 어떤 다른일을 기다리며 , 그 다른일이 끝난후 두번째 print 함수를 수행하고 foo 함수를 종료하고 싶은것 입니다.

 

어떤 함수가 진행을 하다, 다른 프로세스가 돌도록 멈추는 것을

coroutine.yield()

 

라는 것으로 처리 합니다. 즉 프로세스가 위의 라인을 만나면 , 프로세스 진행을 더이상 하지 않고 기다립니다.

물론 위의 함수는 thread 함수가 아닌 일반 함수로 호출하면 오류가 납니다. 그러므로 해당 함수를 thread 로 호출해 줘야 합니다.

 

function foo()
 print("foo",1)
 coroutine.yield()
 print("foo",2)
end

co = coroutine.create(foo)
coroutine.resume(co)

결과

foo 1

위와 같이 foo 함수를 스레드로 만들고 coroutine.resume 으로 해당 스레드 함수를 호출하면 결과가 첫번째 print 함수의 결과만 나옵니다. 그 이유는 resume 에 의하여 해당 foo() 함수가 호출되다가 coroutine.yield() 에서 해당 함수를 돌려주는 프로세스가 멈추게 되는 것이죠.

위의 코드는 coroutine.resume(co) 에 의하여 처음 실행만 되었지, 중간에 yield 된 즉 suspended 된 스레드를 더이상 수행하지 않고 코드가 종료 됩니다. 그러므로 foo() 함수는 suspended 된 후 모든 루아코드가 종료되어 끝나 버린 경우 입니다.

 

function foo()
 print("foo",1)
 coroutine.yield()
 print("foo",2)
end

co = coroutine.create(foo)
print(coroutine.status(co))
coroutine.resume(co)
print(coroutine.status(co))
coroutine.resume(co)
print(coroutine.status(co))

 

결과

suspended  

foo 1            
suspended
foo 2
dead

위와 같이 코드를 바꾸어보죠. 결과를 잘 살펴보시기 바랍니다.

진행 과정은

    <ol dir="ltr" style="list-style-position: initial; list-style-image: initial; margin: 0px 7px 13px 40px; padding: 0px 7px;">
  1. 스레드가 만들어지고 바로 suspended 상태 입니다.
  2. resume 에 의하여 foo 1 이 출력 됩니다.
  3. coroutine.yield() 에 의하여 진행을 더이상하지 않고 멈추어 제어권을 다른곳으로 넘깁니다.
  4. suspended 상태로 있습니다.
  5. resume 에 의하여 앞서 멈춘 thread가 다시 돌아 갑니다. 즉 앞서 정지한 위치부터 프로세스가 돌게되어 foo 2 가 출력됩니다.
  6. thread 함수 즉 foo() 함수가 모두 종료되고 해당 스레드는 죽게 됩니다. (dead 상태)
  7. </ol>

루아에서의 스레드에 대하여 이해가 되셨는지 모르겠습니다.

 

+ Recent posts