본문 바로가기
C++ 200제/코딩 IT 정보

C# 스레드풀 예제, Thread pool + Action + Using

by vicddory 2017. 3. 3.

스레드풀 전체 소스를 소개합니다. 출처는 기억이 안 나는데, 아마도 스택 오버플로우일 겁니다.


프로젝트 압축 파일

C# 쓰레드풀 예제 프로젝트 - ThreadPoolExam.zip


C# 쓰레드풀 소스 (Thread pool runnable example)[C# 쓰레드풀 소스 (Thread pool runnable example)]


아래는 스레드풀 메인 클래스인데, Action을 이용해 랜덤한 스레드 시작과 종료 코드를 실행합니다.


5번째 라인의 thread pool 클래스에서 실제 스레드 객체도 생성합니다.



1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
static void Main(string[] args)
{
    using (var pool = new Pool(5)) // size
    {
        var random = new Random();
        Action<int> randomizer = (index =>
        {
            Console.WriteLine("{0}: Working on index {1}",
                Thread.CurrentThread.Name, index);
 
            Thread.Sleep(random.Next(20400));
 
            Console.WriteLine("{0}: Ending {1}",
                Thread.CurrentThread.Name, index);
        });
 
        for (var i = 0; i < 10++i)
        {
            var i1 = i;
            pool.QueueTask(() => randomizer(i1));
        }
    }
}
cs



다음은 쓰레드풀 클래스의 생성자와 사용되는 변수 4개 입니다. 링크드리스트를 이용해 스레드 객체를 저장하죠.



1
2
3
4
5
6
7
8
9
10
11
// queue of worker thread pools ready to process actions
private readonly LinkedList<Thread> _workers;
 
// actions to be processed by worker threads
private readonly LinkedList<Action> _tasks = new LinkedList<Action>();
 
// set to true when disposing queue but there are still tasks pending
private bool _disallowAdd; 
 
// set to true when disposing queue and no more tasks are pending
private bool _disposed;
cs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public Pool(int size)
{
    this._workers = new LinkedList<Thread>();
 
    for (var i = 0; i < size; ++i)
    {
        var worker = new Thread(this.Worker)
        {
            Name = string.Concat("Worker ", i)
        };
 
        worker.Start();
        this._workers.AddLast(worker);
    }
}
cs



아래는 스레드풀 핵심인 Worker 함수입니다.



1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
private void Worker()
{
    Action task = null;
 
    while (true// loop until thread pool is disposed
    {
        lock (this._tasks) // finding a task needs to be atomic
        {
            while (true// wait for our turn in _workers queue and an available task
            {
                if (this._disposed)
                {
                    return;
                }
 
                // we can only claim a task if its our turn (this worker thread is the first entry in _worker queue) and there is a task available
                if (null != this._workers.First && object.ReferenceEquals(Thread.CurrentThread, this._workers.First.Value) && this._tasks.Count > 0
                {
                    task = this._tasks.First.Value;
                    this._tasks.RemoveFirst();
                    this._workers.RemoveFirst();
                    Monitor.PulseAll(this._tasks); // pulse because current (First) worker changed (so that next available sleeping worker will pick up its task)
                    break// we found a task to process, break out from the above 'while (true)' loop
                }
                Monitor.Wait(this._tasks); // go to sleep, either not our turn or no task to process
            }
        }
 
        task(); // process the found task
 
        lock (this._tasks)
        {
            this._workers.AddLast(Thread.CurrentThread);
        }
        task = null;
    }
}
cs



아래는 스레드풀 실행 결과인데 보시다시피, 랜덤한 실행이 됩니다.



C# 스레드 풀 예제 소스[C# 쓰레드풀 소스 (Thread pool runnable example)]



비동기 기능 구현 시 동기화 등 이슈가 많은데, 스레드풀 사용하면 편합니다.



관련 글



ⓒ written by vicddory

댓글