Maxscript 스레드 분리해서 만들기

 

 

Maxscript는 일반적으로 싱글 스레드로 동작합니다.

그렇다보니 연산량이 많은 경우 실행하고 좀 기다려야 하는데요.

또는 동시에 여러 기능도 작동 시킬 수 없습니다.

스레드를 분리해서 작업하면 위과 같은 경우를 해결 할 수 있습니다.

 

스레드를 분리한다는건 코드를 개별적으로 사용 할 수 있다는 겁니다.

이는 Windows에서 지원하는 DotNet기능을 활용하면 됩니다.

 

스레드를 분리 할 수 있다고해서 모든 코드를 멀티스레드로 할 수 있는건 건데요.

다만 맥스에 영향을 미치는 부분은 스레드 분리를 하면 문제가 발생할 수 있습니다.

충돌이 날 소지가 있다는 겁니다.

 

예) A스레드에서 박스를 생성했는데, B스레드가 삭제함 그런데 A스레드가 다시 박스를 찾음

 

이런경우가 발생하기도 하고 가능하면 기능을 확실히 분리해서 작업하는게 좋겠죠.

맥스와 연동하는 다른 기능이라던가, Maxscript로 네트워크에 접속한다던가 하는 완전히 분리된 기능에 사용해야 합니다.

(스레드가 서로 물기 시작하면 그때부턴 프로그래머의 영역이랄까...)

 

 

예제코드

 

(
global g_ThreadRollout

try (destroyDialog g_ThreadRollout) catch()
rollout g_ThreadRollout "Thread"
(
 progressBar pb0 "Normal" height:25
 button btn_Go0 "go" width:275 height:28

 progressBar pb1 "Thread1" height:25
 button btn_Go1 "Go(Thread)" width:137 height:28 across:2
 button btn_Cancel1 "Cancel(Thread)" width:137 height:28

 progressBar pb2 "Thread2" height:25
 button btn_Go2 "Go(Thread)" width:137 height:28 across:2
 button btn_Cancel2 "Cancel(Thread)" width:137 height:28

 local dno_Thread1
 local dno_Thread2

 fn CreateThread =
 (
  dno_Thread1 = dotNetObject "System.ComponentModel.BackGroundWorker"
  dno_Thread2 = dotNetObject "System.ComponentModel.BackGroundWorker"
  dno_Thread1.WorkerSupportsCancellation = true -- 캔슬 기능을 사용하려면 활성화
  dno_Thread2.WorkerSupportsCancellation = true
 )

 fn Action =
 (
  for i = 1 to 100 do
  (
   sleep 0.03
   pb0.value = i
  )
 )

 fn ActionThread1 sender e =
 (
  for i = 1 to 100 do
  (
   if not dno_Thread1.CancellationPending then -- 캔슬이 되면 걸러진다
   (
    sleep 0.03
    pb1.value = i
   )
   else
    return 0
  )
 )

 fn ActionThread2 sender e  =
 (
  for i = 1 to 100 do
  (
   if not dno_Thread2.CancellationPending then
   (
    sleep 0.03
    pb2.value = i
   )
   else
    return 0
  )
 )

 on btn_Go0 pressed do
 (
  Action() -- 싱글 스레드로 작동되기에 프로그래시바가 진행되고 있는 동안 인터페이스가 얼어 버린다.
 )

 on btn_Go1 pressed do
 (
  if not dno_Thread1.IsBusy then
   dno_Thread1.RunWorkerAsync() -- 스레드가 작동 중이 아니면 실행
 )

 on btn_Cancel1 pressed do
 (
  if dno_Thread1.IsBusy then
   dno_Thread1.CancelAsync() -- 스레드가 작동 중이면 멈춰라
 )

 on btn_Go2 pressed do
 (
  if not dno_Thread2.IsBusy then
   dno_Thread2.RunWorkerAsync() -- 스레드가 작동 중이 아니면 실행

 )

 on btn_Cancel2 pressed do
 (
  if dno_Thread2.IsBusy then
   dno_Thread2.CancelAsync() -- 스레드가 작동 중이면 멈춰라 
 )

 on g_ThreadRollout open do
 (
  CreateThread()
  dotNet.addEventHandler dno_Thread1 "DoWork" ActionThread1 -- 첫번째 스레드에 ActionThread1 함수 등록
  dotNet.addEventHandler dno_Thread2 "DoWork" ActionThread2 -- 두번째 스레드에 ActionThread2 함수 등록
 )

 on g_ThreadRollout close do
 (
  if dno_Thread1.IsBusy then
  dno_Thread1.CancelAsync() -- 스레드가 내부적으로 작동 중이면 종료 시 중지
  if dno_Thread2.IsBusy then
  dno_Thread2.CancelAsync()
  gc()
 )
)
createDialog g_ThreadRollout width:300 height:200
)

 

 

여기에서는 Rollout을 실행할때마다 스레드를 만들었지만

네트워크를 이용할 때 Start 함수에 global로 등록해두고, 주기적으로 실행되더라도 맥스 속도에 큰 영향은 없을 겁니다.

혹은 큰 스크립트의 경우 객채지향 적으로 코드를 만든다면 충분히 활용 할 수 있을 것 같네요.

 

 

Posted by Hwanggoon
,