루아에서의 스레드(Thread)를 설명 드리겠습니다.
이글은 스레드에 대한 개념이 있으셔야 이해하실 수 있습니다. 앞서 설명드린 스레드에 대하여를 우선 읽어 보시기 바랍니다.
루아의 코드는 루아 가상머신이 돌려줍니다. 즉 루아 가상 머신이 스레드를 돌려줘야 합니다.
엄밀히 말하면 C/C++ 로 만든 스레드와는 다릅니다. C/C++ 로 만든 프로그램은 CPU 가 직접(OS 가 직접) 실행하는 코드이지요. 그러나 루아의 코드는 루아 가상머신이 중간에서 돌려주는 역할을 하기때문에, 실질적인 C/C++ 의 스레드를 생각하시면 약간의 오류를 범하실 수 있습니다.
단, 루아의 스레드 역시 하나의 가상머신(이것도 하나의 머신이니까요)에서 돌아주는 스레드 역할을 한다는 것이죠.
루아에서는 스레드를 Coroutine 이라고 합니다.
루아의 coroutine은 간단하게 이렇습니다.
- 루아의 스레드는 함수에서 출발한다.
- 루아의 스레드는 함수단위로 만들수 있다.
- 루아의 스레드는 coroutine 에 의하여 관리된다.
- 루아의 스레드는 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;">스레드가 만들어지고 바로 suspended 상태 입니다.
resume 에 의하여 foo 1 이 출력 됩니다.
coroutine.yield() 에 의하여 진행을 더이상하지 않고 멈추어 제어권을 다른곳으로 넘깁니다.
suspended 상태로 있습니다.
resume 에 의하여 앞서 멈춘 thread가 다시 돌아 갑니다. 즉 앞서 정지한 위치부터 프로세스가 돌게되어 foo 2 가 출력됩니다.
thread 함수 즉 foo() 함수가 모두 종료되고 해당 스레드는 죽게 됩니다. (dead 상태)
</ol>
루아에서의 스레드에 대하여 이해가 되셨는지 모르겠습니다.