Thread.Isalive 동작 방식을 이해를 못하겠어서 질문 드립니다.

if (thread == null)
{
    thread = new Thread(Request);
    thread.Start();
}
else if (thread.IsAlive)
{
    thread.Interrupt();
}
else
{
    thread.Start();
}

맨 처음 Thread 변수가 null이라면 할당 후 돌려주고

돌아가고 있다면 Interrupt

null은 아니지만 멈춰있다면 다시 Start를 해주려고 합니다.

그런데 맨 처음 할당 후 실행을 하고 난 이후에 thread는 IsAlive 상태가 True 여야 된다고 생각을 해서
저렇게 조건을 두고 작성 한 것인데 실제로는 IsAlive가 false로 나오더라고요.

또한 ThreadState도 Stopped로 나오고요.
그런데 실제로는 Thread가 돌아가고 있기 때문에 else 구문에서 다시 실행하게 되면
중복 실행이 안 되는 Exception이 나오게 됩니다.

왜 ISalive 및 threadState가 이렇게 저장되는지 궁금합니다.
또, 제가 생각하는 IsAlive의 기능을 사용하고 싶다면 따로 변수를 실행해서 핸들링 하는 방법밖에 없는지 질문드리고 싶습니다!

감사합니다.

3개의 좋아요

실행이 가능하도록 소스코드를 전부 올려주시면 의견 주시는 분들이 테스트를 직접 하실 수 있을 것 같아 답변이 더욱 정확해질 것 같습니다.

조금 찾아보니 이런 건 있네요

3개의 좋아요

상세 코드가 없어서 질문에 정확한 확인이 어려운거 같습니다.

적어주신 코드로 제가 임의로 테스트 해봤을땐 정상 판단 되고 있었습니다.

public static void Request()
{
    while (true)
    {
        Console.WriteLine("1111111");
        Thread.Sleep(5000);
    }
}

Thread thread = null;
if (thread == null)
{
    thread = new Thread(new ThreadStart(Request));
    thread.Start();
}
else if (thread.IsAlive)
{
    thread.Interrupt();
}
else
{
    thread.Start();
}

Console.ReadLine();

if (thread == null)
{
    thread = new Thread(new ThreadStart(Request));
    thread.Start();
}
else if (thread.IsAlive)  // 스레드 동작 이후 정상 true
{
    thread.Interrupt();
 }
else
{
    thread.Start();
}

추가적으로 스레드가 동작중인지 체크 하시려면
System.Threading.EventWaitHandle
EventWaitHandle 클래스 (System.Threading) | Microsoft Docs

클래스로 신호를 보내서 통보 받거나

CancellationToken 를 활용해서 해당 스레드 작업을 직접 취소 처리해서 스레드 동작 여부를 직접 관리 하시는게 좋을 것 같다고 생각합니다.

* 스레드 중지도 Interrupt() 보단 위에서 제시해드린 CancellationToken를 활용하는 것이 좋아 보입니다.
Interrupt()는 스레드 상태가 대기중일때 중지 되기 때문에 반드시 중지 된다라는 보장이 없습니다.

5개의 좋아요

일단 전부 소스 코드를 올리기에는 클래스나 메서드끼리 엮여있는 부분이 많아서 이렇게 일부만 올린 것인데 오히려 테스트를 하시기 어렵다고 하셔서 앞으로는 최대한 테스트하기 쉽도록 올려보도록 하겠습니다.

감사합니다.

추가로 설명드리자면 현재 프로젝트는 WPF이며, 버튼 이벤트로 동작이 되도록 하였습니다.

또한 초기에 null로 선언을 하였음에도 thread가 할당된 것을 보면 최초 실행된 클래스 인스턴스와 다음부터 실행된 클래스 인스턴스가 동일하다고 생각됩니다.

@aroooong 님이 작성하신 코드를 실제 사용하고 있는 코드와 유사하게 구성 한 결과 똑같은 오류가 발생하는 것으로 보아 제가 사용하고 있는 코드의 구조에서 문제가 발생하는 것 같습니다.

class Program
{
    public async void Request()
    {
        while (true)
        {
            Console.WriteLine("1111111");
            await Task.Delay(5000);
        }
    }

    static void Main(string[] args)
    {
        Program program = new Program();
        program.run();
    }

    void run()
    {
        Thread thread = null;
        if (thread == null)
        {
            thread = new Thread(Request);
            thread.Start();
        }
        else if (thread.IsAlive)
        {
            thread.Interrupt();
        }
        else
        {
            thread.Start();
        }

        Console.ReadLine();

        if (thread == null)
        {
            thread = new Thread(Request);
            thread.Start();
        }
        else if (thread.IsAlive)  // 스레드 동작 이후 정상 true
        {
            thread.Interrupt();
        }
        else
        {
            thread.Start();
        }
    }
}

질문을 부족하게 하여서 죄송합니다…
더 추가 할 만한 점이 있다면 말씀해 주시면 추가 하도록 하겠습니다!

4개의 좋아요

안녕하세요!
일단 제가 정확하게 이해하고 답변다는지 모르겠다는 점 이해 부탁드립니다…

먼저 질문하신 내용을 동일한 상태로 재연하기 위하여 Thread를 전역변수로 변경 후 버튼을 이용하여 run함수를 2회 실행해봤을 때 질문하신 내용으로 IsAlive가 false로 나오면서 ThreadState도 Stopped로 나타나더라구요
(윈폼에서 button을 하나 만들어서 thread를 생성하도록 테스트 하였습니다)

        // Thread를 전역변수로 선언
        Thread thread = null;
        private void button1_Click(object sender, EventArgs e)
        {
            run();
        }

        public async void Request()
        {
            while (true)
            {
                Console.WriteLine("1111111");
                await Task.Delay(5000);
            }
        }

        void run()
        {
            if (thread == null)
            {
                thread = new Thread(new ThreadStart(Request));
                thread.Start();
            }
            else if (thread.IsAlive)
            {
                thread.Interrupt();
            }
            else
            {
                thread.Start();
            }
            Console.ReadLine();
        }

.
.
일단 위와 같은 상태라고 가정하고
해당 방법을 해결하기 위하여 조치한 사항은
비동기 함수인 Request를 동기형식으로 변경했습니다.

AS-IS

TO-BE

근데… 이거 쓰레드에서 비동기 함수를 호출할 경우
Thread 객체를 다시 호출하게 되면 stop 상태인거는 누가 설명해주실수있을까요…

그리고 쓰레드의 상태에 대해서 Interrupt 방식을 사용하는 것보다 좀 더 우아한 종료 방법을 찾는게 좋지 않을까 싶습니다.
https://gipple.tistory.com/15

위 내용 보시고 이상한부분있으면 말씀해주십시요
감사합니다!

2개의 좋아요

방법 자체는 다르지만 비동기 함수를 쓰레드에서 호출하는 경우에 생기는 문제인 것을 단서로 해결 하였습니다.
또한 쓰레드의 상태를 더 우아하게 종료하는 방법에 대해서는 생각해보지 않았는데 새롭게 알게 되서 감사합니다!
그런데 정말 궁금하네요. 왜 비동기 함수를 호출 하였을 때 stop 상태인걸까요…?

언젠가 아시는 분이 오신다면 알려주시면 좋겠습니다!

1개의 좋아요

async 메서드에서 stop이 되는 이유는
디컴파일해서 디버깅을 직접 해보면 알 수 있을거 같은데

일단 조심스런 추측으로는
Awaiter 까지 도달하면 직접 생성해서사용한 thread는 종료되고(여기서 thread상태는 stop)

이후 부터는 스레드풀에서 새로운 스레드로 동작되기 때문이 아닐까라는 조심스럽게 추측해봅니다…ㅎㅎ

2개의 좋아요

오 찾은거 같습니다 (아마)
아래 링크에 대한 설명이 딱 맞는거 같습니다.

먼저 async/await 함수를 사용할때는 return 을 Task로 하게 되어있는데
Thread 함수를 사용할때는 return void 형식이라 맞지 않은거 같습니다.

결과적으로 async/await 함수를 사용하려면 Task를 이용한 함수 호출을 해야한다 입니다. (링크 예제3)

3개의 좋아요