|
장성호님이 친절하게 설명해주셨는데, 왕초보님이 아직 잘 이해하지 못하신 부분이 있는 것 같아 조금 보충해봅니다. (장성호님의 답변에는 친절함 뿐만 아니라 자세함과 정확함에도 정말 놀랬습니다 ^^)
별도의 쓰레드를 돌리지 않는 한, 모든 프로그램(정확하게는 프로세스)은 하나의 쓰레드에서 돌아갑니다. 이걸 디폴트 쓰레드라고 합니다. 그리고 모든 쓰레드 안에서 코드의 흐름은 무조건 순차적입니다. 다만 그것이 메시지와 이벤트를 통해 비순차적으로 동작하는 것처럼 보일 뿐입니다. 내부적으로 흐름은 항상 순차적입니다.
따라서 기본적으로는 하나의 함수가 끝나기 전에 다른 함수가 실행되는 것은 불가능합니다. 다만, 장성호님이 말씀하신 Application->ProcessMessages()를 중간에 넣으면, 이 함수가 대기중인 다른 메시지들을 처리합니다만, 이 경우에는 이 함수 자체 내에서 시간을 까먹으면서 대기중인 메시지들 처리만 하고, 처리가 끝난 후에야 돌아옵니다.
타이머를 두개 돌린다고 해도 쓰레드는 디폴트 쓰레드 하나 뿐입니다. 이건 타이머를 하나만 돌리는 경우에도 당연히 마찬가지여서, 타이머의 이벤트 핸들러가 실행되는 중에는 다른 어떤 작업도 처리되지 않습니다. 타이머의 동작에 10초가 걸린다면, 10초동안 프로그램이 먹통이 됩니다. 따라서 사용자는 답답함을 느끼게 되겠지요.
여기에는 그 핸들러 자신에 대한 재진입도 포함되어서, 타이머의 이벤트 핸들러가 실행되고 있는 중에는 핸들러 자체도 다시 실행되지 않습니다. 그래서 윈도우의 다른 대부분의 메시지들은 프로그램이 다른 처리 때문에 바쁜 동안에는 메시지 큐에 계속 대기하고 있다가 차례가 오면 언젠가는 실행되지만, 타이머 메시지는 메시지 대기열에 있다가도 무시될 수 있게 되어 있습니다. 1초에 10번 발생하는 타이머가 있다고 할 때 그 처리가 0.5초씩 걸린다면, 타이머 메시지가 쌓이는 속도가 처리되는 속도보다 빨라서, 프로그램은 다른 거의 대부분의 작업을 하지 못해 먹통이 될 것이니까요.
이런 이유로, 프로그램에서 일정 조건에서 반드시 실행되어야 하는 중요한 작업들을 타이머 이벤트로 처리하는 것은 문제의 소지가 많습니다. 발생한 타이머 메시지가 사라질 가능성이 있기 때문입니다. 이건, 타이머 메시지의 처리 시간(이벤트 핸들러의 실행 시간)이 Interval보다 훨씬 빨라서 문제가 될 거 같지 않다고 해도 실제로 프로그램을 돌려보면 그런 문제가 발생할 가능성이 얼마든지 있습니다.
컴퓨터는 해당 프로그램에만 100%의 시간을 할당하지 않기 때문에, 경우에 따라 다른 프로그램이 우선적으로 CPU 타임을 할당받아가는 바람에 우리 프로그램에는 처리할 시간이 돌아오지 않아서 적절한 시점에서 타이머 이벤트가 발생하지 않을 수 있습니다.
간단히 요약하자면, 타이머 이벤트에서는 한번 실행되지 않더라도 다음번 실행에서 커버할 수 있는 작업만을 해야 합니다. 간단한 예를 들면, 1초에 한번 발생하는 타이머 이벤트에서 한번 실행할 때마다 0으로 초기화된 변수에 1씩 더하는 코드를 작성하고 100초가 지났을 때 변수가 100이 되었을 거라는 가정을 하면 안됩니다. 이 문제를 피하려면, 처음 실행되었을 때의 시간을 기억해둔 후 타이머에서는 그 시간과 현재 시간 사이의 초를 따져야 합니다.
다시 말씀드리지만, 반드시 한번 한번의 실행이 중요한 코드는 타이머 이벤트에 넣어서는 안되며, 가끔씩 무시되어 실행되지 않더라도 문제가 되지 않는 경우에만 타이머를 써야 합니다. 그게 안된다면, 무조건 쓰레드를 써야 합니다. 익숙한 개발자들에게조차도 쓰레드를 쓰는 것은 귀찮은 일인데도 쓰레드가 존재하고 많이 사용되는 것은 바로 이런 이유 때문입니다.
그럼...
왕초보 님이 쓰신 글 :
: 우선 답글 너무 감사합니다 많은 도움이 되었습니다.
:
: 한가지 아직 이해가 잘 안되는게 있는데..
:
: 그렇다면 쓰레드를 사용하지 않고 타이머 두개를 동시에 돌릴수 있는 방법이 있을까요?
:
: 아무리 해도 두가지 이벤트를 동시에 실행시키면
:
: 하나의 이벤트의 타이머가 끝날때까지 다른 하나의 이벤트의 타이머는 대기 하고 있다가
:
: 끝나면 실행되더라구요..
:
: 답변 좀 부탁드립니다..
:
:
: 장성호 님이 쓰신 글 :
: : 먼저 컴퓨터에서 프로그램이 동시에 돌아갈수는 없습니다.
: : 쓰레드로 돌려도 동시는 아닙니다.
: :
: : 윈도우에 프로그램이 여러개 떠있어
: : 여러 프로그램이 동시에 실행되서 돌아가지만
: :
: : 사실은 윈도우가 아주 짧은시간간격으로
: : 쓰레드단위로 조금씩 cpu자원을 쓰레드에 할당해주는겁니다.
: : 사람은 못느낄 정도로..
: : 애쪼금, 제쪼금,게쪼끔...
: : 이런걸 멀티테스킹이라고 그러죠..
: :
: : 그런데 어떤 프로그램이 while문에 빠져서 못나오고 있다면
: : 그 프로그램이 cpu자원을 너무 많이 쓰기때문에
: : 원도우전체가 버벅 거리게 됩니다.
: :
: :
: : 서론이 길었네요
: : 타이머에서
: :
: : 1.
: : 타이머가 두개일때 하나씩 이벤트 핸들러 함수가 호출됩니다. 차례차례
: : 타이머를 두개 올려놓고 각 1초 씩 주고
: : 둘중 하나의 타이머 핸들러 함수에서 Sleep(3000) 3초 정도 줘 보십시요
: : 그리고 이벤트 발생하면 Label에 Count하면서 뿌려보십시요
: :
: : 1번 타이머는 천천히 돌고 2번 타이머는 빨리돌까요?
: : 아닙니다 같이 올라갑니다.
: :
: : Sleep(3000)동안 아무 작업을 안하는 겁니다.
: :
: :
: : 2. 그리고 하나의 타이머에서 타이머가 1초짜리인데
: : 작업하는 시간이 3초 걸리면 작업중에 또 이벤트가 발생할까요?
: : 아닙니다.
: : 작업이 끝나야 이벤트가 발생합니다.
: : 그리고 끝나고 1초후에 발생하는것이 아니라 곧바로 이벤트가 발생합니다.
: : 왜냐면 3초작업동안 이미 interval 1초가 지났으니까요..
: :
: : 3. 1초짜리 타이머에서 작업이 3초 걸리는경우 작업중에 다시 타이머 이벤트가 발생하려면
: : 작업 중간중간에 Application->ProcessMessages();를 넣으면 가능합니다.
: : 그러나 그렇게 하면 재귀함수 비슷하게 되므로 문제가 있습니다.
: : 절대 Timer이벤트 함수안에 Application->ProcessMessages();넣지 마시길
: :
: : 4. Application->ProcessMessages();를 Timer핸들러 함수에 넣을수도 있어요
: : 그런경우엔 Timer 함수 시작부분에 Timer1->Enabled=false 한후
: : 함수 끝에 Timer1->Enabled=true 하는식으로 하시길...
: :
: :
: :
|