programing

C # 스레드가 잠들지 않습니까?

firstcheck 2021. 1. 14. 08:33
반응형

C # 스레드가 잠들지 않습니까?


이 코드가 있습니다.

void Main()
{
    System.Timers.Timer t = new System.Timers.Timer (1000);
    t.Enabled=true;
    t.Elapsed+= (sender, args) =>c();
    Console.ReadLine();

}

int h=0;
public void c()
{
    h++;
    new Thread(() => doWork(h)).Start();
}

public void doWork(int h)
{
    Thread.Sleep(3000);
    h.Dump();
}

간격이 1000ms이고 작업 프로세스가 3000ms이면 어떻게되는지보고 싶었습니다.

그러나 이상한 동작을 보았습니다. 3000ms 지연 은 시작시에만 발생합니다 !

어떻게 각 doWork수면을 3000ms로 만들 수 있습니까?

여기에서 볼 수 있듯이 처음에는 3 초의 지연이 있고 각각 1 초씩 반복됩니다.

여기에 이미지 설명 입력


타이머가 틱할 때마다 잠자기 작업을 수행하기 위해 스레드를 시작합니다. 해당 스레드는 완전히 격리되어 있으며 타이머는 매초마다 계속 실행됩니다. 실제로 타이머 이동 하더라도 매초마다 실행됩니다 .Sleep(3000)c()

현재 가지고있는 것은 :

1000 tick (start thread A)
2000 tick (start thread B)
3000 tick (start thread C)
4000 tick (start thread D, A prints line)
5000 tick (start thread E, B prints line)
6000 tick (start thread F, C prints line)
7000 tick (start thread G, D prints line)
8000 tick (start thread H, E prints line)
...

무엇을하려고하는지 확실하지 않습니다. 타이머가 실행되는 것을 원하지 않을 때 타이머를 비활성화하고 준비가되면 다시 재개 할 수 있지만 그 목적이 무엇인지는 확실하지 않습니다 Sleep(). 또 다른 옵션은 그 안에있는 while루프입니다 Sleep(). 간단하고 많은 스레드를 포함하지 않습니다.


매초마다 3 초 지연으로 새 스레드를 시작합니다. 다음과 같이 발생합니다.

  1. 스레드 1 시작
  2. 스레드 2 시작, 스레드 1 휴면
  3. 스레드 3 시작, 스레드 2 휴면, 스레드 1 휴면
  4. 스레드 4 시작, 스레드 3 휴면, 스레드 2 휴면, 스레드 1 휴면
  5. 스레드 5 시작, 스레드 4 휴지, 스레드 3 휴지, 스레드 2 휴지, 스레드 1 덤프
  6. 스레드 6 시작, 스레드 5 휴지, 스레드 4 휴지, 스레드 3 휴지, 스레드 2 덤프
  7. 스레드 7 시작, 스레드 6 휴지, 스레드 5 휴지, 스레드 4 휴지, 스레드 3 덤프

보시다시피 각 스레드는 3 초 동안 휴면하지만 매초마다 덤프가 발생합니다.

스레드와 어떻게 작동합니까? 이 같은 smth :

void Main()
{
    new Thread(() => doWork()).Start();
    Console.ReadLine();
}

public void doWork()
{
    int h = 0;
    do
    {
        Thread.Sleep(3000);
        h.Dump();
        h++;
    }while(true);
}

귀하의 예는 매우 흥미 롭습니다. 병렬 처리의 부작용을 보여줍니다. 귀하의 질문에 답하고 부작용을 더 쉽게 볼 수 있도록 귀하의 예를 약간 수정했습니다.

using System;
using System.Threading;
using System.Diagnostics;

public class Program
{
    public static void Main()
    {
        (new Example()).Main();
    }
}

public class Example
{
    public void Main()
    {
        System.Timers.Timer t = new System.Timers.Timer(10);
        t.Enabled = true;
        t.Elapsed += (sender, args) => c();
        Console.ReadLine(); t.Enabled = false;
    }

    int t = 0;
    int h = 0;
    public void c()
    {
        h++;
        new Thread(() => doWork(h)).Start();
    }

    public void doWork(int h2)
    {
        Stopwatch sw = new Stopwatch();
        sw.Start();
        try
        {
            t++;
            Console.WriteLine("h={0}, h2={1}, threads={2} [start]", h, h2, t);
            Thread.Sleep(3000);
        }
        finally
        {
            sw.Stop();
            var tim = sw.Elapsed;
            var elapsedMS = tim.Seconds * 1000 + tim.Milliseconds;
            t--;
            Console.WriteLine("h={0}, h2={1}, threads={2} [end, sleep time={3} ms] ", h, h2, t, elapsedMS);
        }
    }
}

여기에서 수정 한 내용은 다음과 같습니다.

  • 타이머 간격은 이제 10ms이고 스레드는 여전히 3000ms입니다. 그 결과 스레드가 휴면 상태 일 때 새 스레드가 생성됩니다.
  • t현재 활성화 된 스레드 수를 계산하는 varialbe를 추가했습니다 (스레드가 시작될 때 증가하고 스레드가 끝나기 직전에 감소됨).
  • 스레드 시작과 스레드 끝을 인쇄하는 2 개의 덤프 문을 추가했습니다.
  • Finally, I've given the parameter of function doWork a different name (h2), which allows to see the value of the underlying variable h

Now it is intersting to see the output of this modified program in LinqPad (note the values are not always the same as they're depending on the race conditions of the started threads):

    h=1, h2=1, threads=1 [start]
    h=2, h2=2, threads=2 [start]
    h=3, h2=3, threads=3 [start]
    h=4, h2=4, threads=4 [start]
    h=5, h2=5, threads=5 [start]
    ...
    h=190, h2=190, threads=190 [start]
    h=191, h2=191, threads=191 [start]
    h=192, h2=192, threads=192 [start]
    h=193, h2=193, threads=193 [start]
    h=194, h2=194, threads=194 [start]
    h=194, h2=2, threads=192 [end]
    h=194, h2=1, threads=192 [end]
    h=194, h2=3, threads=191 [end]
    h=195, h2=195, threads=192 [start]

I think the values speak for themselves: What is happening is that every 10 ms a new thread is started, while others are still sleeping. Also interesting is to see that h is not always equal to h2, especially not if more threads are started while others are sleeping. The number of threads (variable t) is after a while stabilizing, i.e. running around 190-194.

You might argue, that we need to put locks on the variables t and h, for example

readonly object o1 = new object(); 
int _t=0; 
int t {
       get {int tmp=0; lock(o1) { tmp=_t; } return tmp; } 
       set {lock(o1) { _t=value; }} 
      }

While that is a cleaner approach, it didn't change the effect shown in this example.

Now, in order to prove that each thread really sleeps 3000ms (= 3s), let's add a Stopwatch to the worker thread doWork:

public void doWork(int h2) 
{ 
    Stopwatch sw = new Stopwatch(); sw.Start();
    try 
    {
        t++; string.Format("h={0}, h2={1}, threads={2} [start]", 
                            h, h2, t).Dump();                               
        Thread.Sleep(3000);         }
    finally {
        sw.Stop(); var tim = sw.Elapsed;
        var elapsedMS = tim.Seconds*1000+tim.Milliseconds;
        t--; string.Format("h={0}, h2={1}, threads={2} [end, sleep time={3} ms] ", 
                            h, h2, t, elapsedMS).Dump();
    }
} 

For a proper cleanup of the threads, let's disable the timer after the ReadLine as follows:

    Console.ReadLine(); t.Enabled=false; 

This allows you to see what happens if no more threads are starting, after you've pressed ENTER:

    ...
    h=563, h2=559, threads=5 [end, sleep time=3105 ms] 
    h=563, h2=561, threads=4 [end, sleep time=3073 ms] 
    h=563, h2=558, threads=3 [end, sleep time=3117 ms] 
    h=563, h2=560, threads=2 [end, sleep time=3085 ms] 
    h=563, h2=562, threads=1 [end, sleep time=3054 ms] 
    h=563, h2=563, threads=0 [end, sleep time=3053 ms] 

You can see they are all being terminated one after the other as expected and they slept about 3s (or 3000ms).


The reason you see this behavior is simple: you schedule a new thread each second, with the result becoming visible three seconds later. You do not see anything for the first four seconds; then, the thread that has been started three seconds ago dumps; another thread will have been sleeping for two seconds by then, and yet another - for one second. The next second thread #2 dumps; then thread #3, #4, and so on - you get a printout every second.

If you would like to see a printout every three seconds, you should schedule a new thread every three seconds with any delay that you would like: the initial thread will output in three seconds plus the delay; all the subsequent threads will be firing on three-second intervals.


매초마다 새 스레드를 실행하는 것 같습니다. 좋은 생각이 아닙니다. backgroundworker를 사용하고 이벤트 backgroundworker가 완료되면 C 함수를 다시 호출하면 타이머가 필요하지 않습니다.


각 doWork는 3 초 동안 휴면 상태이지만 1 초 간격으로 스레드를 생성하기 때문에 휴면 시간이 겹칩니다.

참조 URL : https://stackoverflow.com/questions/11307819/c-sharp-thread-wont-sleep

반응형