2014년 4월 29일 화요일

닷넷, C#에서 쓰레드(Thread) 다루기, 닷넷네트워크의 기본이 쓰레드입니다. C#공부 열심히 하세요

닷넷, C#에서 쓰레드(Thread) 다루기, 닷넷네트워크의 기본이 쓰레드입니다. C#공부 열심히 하세요


쓰레드(Thread)
쓰레드란 CPU를 이용하는 가장 작은 단위인데 싱글 쓰레드를 사용하면 CPU의 사용 권한을 하나의 쓰레드가 독차지 하게 된다. 지하철 개찰구의 예를들면 개찰구가 하나라면 평상시에는 큰 무리가 아니지만 출퇴근 시간에는 무리가 따를 수 있다. 결국 개찰구를 늘여야 한다는 것이다. 프로그래밍에서 볼 때 개찰구를 늘이는 것이 멀티 쓰레드를 이용하는 것이다. 멀티 쓰레드가 제대로 동작하기 위해서는 CPU가 여러 개 있어야 한다. 보통은 단일 CPU를 사용 할 것이다. CPU는 한번에 하나의 쓰레드를 사용하므로 멀티 쓰레드 프로그램이 실행되는 경우에는 CPU의 사용 시간을 나누어서 각각의 쓰레드에게 나누어 주는 것이다. 결국 개찰구는 늘였지만 표를 파는 곳은 한 군데 인것이다.

C#에서의 멀티 쓰레드

C#에서 멀티 쓰레드를 사용하는 방법은 기 정의된 쓰레드 클래스를 사용하면 된다. 결국 배워야 하는 것은 C#에서 멀티 쓰레드를 위한 클래스가 어떤 것이 있고 그 사용법은 어떻게 되는가 이다. 쓰레드를 위한 개체들은 System.Threading 네임스페이스 안에 정의 되어 있다.

[첫번째 예제]
using System;
using System.Threading;

public class ThreadTest
{
public void FirstWork()
{
for(int i=0; i < 100; i++) >
{
Thread.Sleep(1000); //밀리세컨드 단위
Console.Write("F{0} " ,i);
}
}

public void SecondWork()
{
for(int i=0; i < 100; i++) >
{
Thread.Sleep(1000);
Console.Write("S{0} " ,i);
}
}

[MTAThread]
public static void Main()
{
ThreadTest t = new ThreadTest();

//Thread는 생성자에 ThreadStart형 Delegate를 인자로 받는다.
Thread first = new Thread(new ThreadStart(t.FirstWork));
Thread second = new Thread(new ThreadStart(t.SecondWork));

first.Start();
second.Start();
}
}

[예제1-1]
using System;
using System.Threading;
class ThreadTest
{
static void Thmethod()
{
int id = AppDomain.GetCurrentThreadId();
Console.WriteLine("Thread[{0}] Thmethod Method Running",id);
}
static void Main()
{
int id = AppDomain.GetCurrentThreadId();
Console.WriteLine("Main Thread[{0}]",id);
for(int i=0;i<10;i++) >
{
Thread th = new Thread(new ThreadStart(Thmethod));
th.Start();
}
}
}


Thread.Sleep 안에는 해당 Thread가 얼마만큼 쉴 건지에 대한 시간을 밀리 세컨드단위로 지정 한다. 만약 시간을 0으로 설정하면 현재 자신에게 주어진 시간을 다른 쓰레드에게 쓰게 하겠다는 의미이다. 지금 당장은 CPU를 사용 하지 않아도 될 때 다른 쓰레드에게 CPU를 사용 할 기회를 줌으로써 CPU를 효율적으로 이용 할 수 있다. 쓰레드를 쉐게 하는 방법은 Thread.Suspend 를 이용 할 수도 있다. Sleep과의 차이는 Sleep인 경우엔 지정한 시간 만큼 쉰다는 의미지만 Suspend인 경우엔 Resume 메소드를 호출 할 때 까지 쉬게 된다는 것이다.또 다른 차이점은 Sleep 메소드는 자기 자신의 쓰레드만 쉬게 할 수 있다. 반면에 Suspend 는 자기 뿐 아니라 다른 쓰레드도 쉬게 할 수 있다.잠을 자고 있는 Thread가 스스로 깰 수는 없다. 그래서 Suspend로 쉬고 있는 쓰레드는 다른 쓰레드가 Resume을 이용하여 깨울 때 까지 쉬고 있는 것이다. 주의 할 점은 Sleep인 경우는 쓰레드가 즉시 중단 되지만 Suspend로 쉬게 할려면 즉시 중단 되지 않는다.

[예제2]
using System;
using System.Threading;

public class ThreadTest2
{
public bool sleep = false;
public void FirstWork()
{
for(int i=0; i < 10; i++) >
{
Console.WriteLine("F{0}", i);
if (i == 5)
{
sleep = true;
Console.WriteLine("");
Console.WriteLine("first 쉼...");
Thread.CurrentThread.Suspend();
}
}
}
}

class TestMain
{
[MTAThread]
public static void Main()
{
ThreadTest2 t = new ThreadTest2();
Thread first = new Thread(new ThreadStart(t.FirstWork));

first.Start();

while(t.sleep == false) {}

Console.WriteLine("");
Console.WriteLine("first를 깨웁니다...");
first.Resume();
}
}
Suspend 메소드로 쓰레드를 잠시 중지하면 Resume 메소드로 다시 동작하게 할 수 있지만 Thread.Abort로 일단 쓰레드를 종료 시키면 다시 되살릴 수 없다.쓰레드가 확실히 종료 되었는지를 살펴보기 위해서는 Thead.Join 메소드를 사용 할 수 있는데 Thread.Join 메소드는 동기적으로 동작하므로 쓰레드가 종료 할 때까지 기다리게 된다. 만일 어떤 이유에서든지 쓰레드가 종료 되지 않는 다면 무한정 기다릴 수 밖에 없다. Thread.Join 메소드 안에 1/1000초 단위로 파라미터를 전달 할 수 있는데이것은 얼마 만큼 Join으로 붙은 쓰레드가 종료 될 때까지 기다릴 수 있는 가에 대한 값이다. 만일 주어진 시간안에 종료되면 true를 반환하고 기다리기를 중지 한다면 false 값을 반환 한다.

쓰레드가 여러 개 있다면 한 쓰레드가 동작하고 나서 어떤 쓰레드가 동작 할까? 아마도 높은 우선 순위를 가지고 있는 쓰레드가 수행 될 것이다. 각각의 쓰레드는 CPU 사용 권한에 대한 우선 순위가 있는데 우선 순위가 높을수록 CPU사용 권한을 먼저 할당 받는다.

아래의 예제를 보도록 하자.

using System;
using System.Threading;

public class ThreadTest3
{
public bool sleep = false;
public void FirstWork()
{
for(int i=0; i < 10; i++) >
{
for(int j=0; j < 10; j++) >
{
Thread.Sleep(100);
Console.Write(",");
}

Console.WriteLine("F{0}", i);
}
}

public void SecondWork()
{
for(int i=0; i < 10; i++) >
{
for(int j=0; j < 10; j++) >
{
Thread.Sleep(100);
Console.Write(",");
}

Console.WriteLine("S{0}", i);
}
}
}

class TestMain
{
[MTAThread]
public static void Main()
{
ThreadTest3 t = new ThreadTest3();
Thread first = new Thread(new ThreadStart(t.FirstWork));
Thread second = new Thread(new ThreadStart(t.SecondWork));

first.Start();
second.Start();
}
}

위의 예제를 실행해 보면 각각의 쓰레드가 할당 받은 시간이 비슷함을 알 수 있다. 두개의 쓰레드가 우선 순위가 비슷 하니까 아래의 그림과 같은 결과가 나오는 것이다.



아래의 예는 Join을 이용한 예제이다.
first.Join() 부분을 주석으로 막은 후 다시 실행 해 보라.

using System;
using System.Threading;

public class ThreadTest2
{
public int[] iArray = new int[100];
public void CollectData()
{
for(int i=0; i <= 20; i++) >
{
iArray[i] = i+1;
Console.Write(",");
Thread.Sleep(500);
}
}
}

class TestMain
{
[MTAThread]
public static void Main()
{
ThreadTest2 t = new ThreadTest2();
Thread first = new Thread(new ThreadStart(t.CollectData));

first.Start();
first.Join();

int sum=0;
for(int i=0; i
{
sum += t.iArray[i];
}

Console.WriteLine();
Console.WriteLine("sum = {0}", sum);
}
}


한 쓰레드에 대해 우선순위를 높여 주면 CPU 사용 권한을 우선적으로 갖는 것이다. Thread의 우선 순위와 관련된 프로퍼티가 있는데 열거형 값인 Highest, AboveNormal, Normal, BelowNormal, Lowest중 한 값이다. 아래의 예제를 살펴 보자.


using System;
using System.Threading;

public class ThreadTest3
{
public bool sleep = false;
public void FirstWork()
{
for(int i=0; i < 10; i++) >
{
for(int j=0; j < 10; j++) >
{
Thread.Sleep(100);
Console.Write(",");
}

Console.WriteLine("F{0}", i);
}
}

public void SecondWork()
{
for(int i=0; i < 10; i++) >
{
for(int j=0; j < 10; j++) >
{
Thread.Sleep(100);
Console.Write(",");
}

Console.WriteLine("S{0}", i);
}
}
}

class TestMain
{
[MTAThread]
public static void Main()
{
ThreadTest3 t = new ThreadTest3();
Thread first = new Thread(new ThreadStart(t.FirstWork));
Thread second = new Thread(new ThreadStart(t.SecondWork));

first.Priority = ThreadPriority.Lowest;

first.Start();
second.Start();
}
}



멀티쓰레드 환경인 경우 여러 곳에서 같은 객체의 메소드를 호출 하는 경우에 예기치 않은 결과가 나타날 수 있다. 어떤 메소드의 사용을 한 쓰레드가 끝난 후 다른 쓰레드가 접근하게 하려면 lock 문을 사용 한다. 다음의 예제를 보도록 하자.


using System;
using System.Threading;

public class ThreadTest3
{
public string lockString = "Hello";
public void Print(string rank)
{
//lock을 걸어준 구문은 처음 쓰레드가 끝날때 까지 다른 쓰레드가 접근 금지
lock (this)
{
for(int i=0; i < 10; i++) >
{
for(int j=0; j < 10; j++) >
{
Thread.Sleep(100);
Console.Write(",");
}

Console.WriteLine("{0}{1} ", rank, lockString);
}
}
}

public void FirstWork()
{
Print("F");
}

public void SecondWork()
{
Print("S");
}
}

class TestMain
{
[MTAThread]
public static void Main()
{
ThreadTest3 t = new ThreadTest3();
Thread first = new Thread(new ThreadStart(t.FirstWork));
Thread second = new Thread(new ThreadStart(t.SecondWork));

first.Start();
second.Start();
}
}


lock 문 이외에 System.Monitor라는 클래스가 있는데 이 Monitor 클래스에는 Enter,Exit 메소드가 있는데 Enter 메소드는 잠금 상황으로, Exit 메소드는 잠금을 해제하는 역할을 한다. 앞에서 작성한 예제를 System.Monitor를 이용하는 예문으로 바꿔 보자…

using System;
using System.Threading;

public class ThreadTest3
{
public string lockString = "Hello";
public void Print(string rank)
{
//lock을 걸어준 구문은 처음 쓰레드가 끝날때 까지 다른 쓰레드가 접근 금지
Monitor.Enter(this);
for(int i=0; i < 10; i++) >
{
for(int j=0; j < 10; j++) >
{
Thread.Sleep(100);
Console.Write(",");
}

Console.WriteLine("{0}{1} ", rank, lockString);
}
Monitor.Exit(this);
}

public void FirstWork()
{
Print("F");
}

public void SecondWork()
{
Print("S");
}
}

class TestMain
{
[MTAThread]
public static void Main()
{
ThreadTest3 t = new ThreadTest3();
Thread first = new Thread(new ThreadStart(t.FirstWork));
Thread second = new Thread(new ThreadStart(t.SecondWork));

first.Start();
second.Start();
}
}

오라클자바커뮤니티에서 운영, 개발자 전문교육, 개인80%환급 오엔제이프로그래밍실무교육센터(www.onjprogramming.co.kr)

평일주간(9:30~18:20) 개강
(5/12)C#4.0,ADO.NET,Network 프로그래밍
(5/12)[기업100%환급]자바기초에서 JDBC, Servlet/JSP까지
(5/12)[기업100%환급]Spring ,MyBatis,Hibernate실무과정
(5/12)안드로이드개발자과정
(5/19)[기업100%환급]PL/SQL,ORACLE HINT,TUNING
(5/21)[교육전취업확정]Spring,MyBatis,XPlatform실무프로젝트과정
(5/26)[기업100%환급]SQL기초에서 Schema Object까지

평일야간(19:00~21:50) 개강
(5/07)Spring3.X, MyBatis, Hibernate실무과정
(5/09)웹퍼블리싱 마스터
(5/09)JAVA&WEB프레임워크실무과정
(5/09)SQL초보에서실전전문가까지
(5/16)자바웹(JSP,Spring,MyBatis,XPlatform)프로젝트과정
(5/16)C#,ASP.NET마스터
(5/19)안드로이드개발자과정
(5/20)개발자를위한PLSQL,SQL튜닝,힌트

주말(10:00~17:50) 개강
(5/03)안드로이드개발자과정
(5/03)C#,ASP.NET마스터
(5/03)JAVA&WEB프레임워크실무과정
(5/10)자바기초에서JSP,Ajax,jQuery,Spring3.2,MyBatis까지
(5/10)닷넷실무자를위한WPF개발자과정
(5/10)SQL초보에서실전전문가까지
(5/10)Spring3.X, MyBatis, Hibernate실무과정
(5/11)웹퍼블리싱 마스터
(5/17)개발자를위한PLSQL,SQL튜닝,힌트

주말저녁(18:30~22:20) 개강
(5/17)자바&웹,jQUERY,스프링프레임워크
(5/17)SQL기초에서 Schema Object까지

댓글 없음:

댓글 쓰기