쓰레드 이벤트 사용시
자주쓰는 TIP
1.Queue 큐// Stack 스택
<Stack>
: 입력한데이터가 가장 위에 쌓이고 가장 위 데이터를 가져오는 방식
Stack<string> stack = new Stack<string>();
삽입 : Push ==> stack.push("1");
빼낼 데이터 확인 : Peek (stack, queue 같음) string st = stack.peak();
빼냄 : Pop ==> 마지막 데이터를 뺸 나머지 저장
<Queue>
: 입력한데이터가 순서대로 쌓이는 가장먼저 입력을 가져가는 방식
Queue<string> queue = new Queue<string>(); //큐사용시
삽입 : Enqueue queue.Enqueue("1");
빼낼 데이터 확인 : Peek (stack, queue 같음)
string pop = queue.Dequeue(); // Dequeue: 맨 처음 데이터 '빼냄'
Console.WriteLine("Pop : " + pop);
빼냄 : Dequeue
/* 결과
Peek : 1
queue : 1,2,3,4
Pop : 1
queue : 2,3,4
*/
2. this.Invoke(new Action(() =>{ label1.Text = "대기중";}));
대리자 (delegate)
this.Invoke(new MethodInvoker(
delegate()
{
///실행할 내용
lstLog.Items.Add(new ListViewItem(strData));
}
)
);
하나의 Form을 다른 thread에서 접근하게 될 경우에 기존의 Form과 충돌이 날 수 있다.
이 때 invoke 를 사용하여 실행하려고 하는 메소드의 대리자(delegate)를 실행시키면 된다.
예를 들어 myFormControl.Invoke(myformControl.myDelegate) 인자로 받은
Form Instance/form에 딸린 Invoke/인자로 받은 Form Instance에 들어 있는 함수를 대리하는 Delegate
멀티스레드 환경에서 데이터 보호를 위해 Invoke를 써야 합니다.
응용 프로그램이 실행될 때 기본적으로 하나의 스레드가 발생합니다.
이것을 Main 스레드라고 부르는 이유는 Main() 함수가 이 스레드의 시작점이기 때문입니다.
Main() 함수를 보시면 폼을 띄우죠? 결국 메인 스레드가 메인폼의 이벤트 처리를 담당하면서
메인폼의 각종 컨트롤들의 값을 읽고 쓰는 작업을 수행합니다.
메인폼에서 다른 폼을 띄울 경우에도 기본적으로 메인 스레드가 자식 폼의 컨트롤들까지 모두 소유합니다.
그런데, 별도의 스레드에서 폼의 컨트롤을 액세스하면 데이터(컨트롤?)가 깨질 수 있습니다.
멀티스레드에 관해 조금이나마 공부해 보셨다면 이해하실 겁니다.
따라서, 별도의 스레드는 메인 스레드에게 컨트롤을 읽고 쓰는 작업을 위임하여 수행하게 하면 안전하겠죠.
그래서, 외부 스레드가 메인폼의 Invoke 를 호출하는 것입니다.
[별도의 스레드]에서 [main_form.Invoke(xxx) 를 호출] 한다는 것은,
[별도의 스레드]가 [main_form 을 소유한 스레드]에게 [xxx 함수의 호출을 위임]한다는 뜻 입니다.
3. AutoResetEvent
Queue<string> queue = new Queue<string>(); //큐사용시
AutoResetEvent autoResetEvent = new AutoResetEvent(false);
Thread th = null;
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
th = new Thread(new ThreadStart(Logic));
th.IsBackground = true;
th.Start();
}
//프로토콜 데이터를 수신해서 처리하는 부분.
private void Logic()
{
while(true)
{
int queCount = 0;
lock(queue) //
{
queCount = queue.Count;
}
if(queCount ==0)
{
this.Invoke(new Action(() =>
{
label1.Text = "대기중";
}));
//데이터가 들어올 때 까지 대기.
//처리할데이터가X
autoResetEvent.WaitOne();
}
else
{
//TCP프로토콜 형태로 다른시스템에 전달...
//DB에 데이터를 저장..
//파일에 데이터를 저장..
//오래걸릴 가능성있습니다.
//데이터를 처리하는 부분
//총2회 실행//많은데이터가 들어온다고해도. 순차적으로 처리,하나하나 처리하는 것
this.Invoke(new Action(() =>
{
label2.Text += queue.Dequeue();
}));
}
}
}
private void button1_Click(object sender, EventArgs e)
{
//프로토콜 데이터를 수신한다고 가정...
//TCP로부터 데이터를 수신,UDP네트워크통신,Serial 프로토콜로 데이터를 수신
//프로토콜로 받은데이터를 수신 후 Queue
queue.Enqueue("100");
queue.Enqueue("100");
autoResetEvent.Set();//처리할 데이터가 신호보냄.
}
[C#] TCP 통신 (0) | 2023.09.11 |
---|---|
C# 단축키 (0) | 2023.09.06 |
[C#] 시리얼 통신이란 (0) | 2023.08.03 |
[C#] Timer 쓰는 법 (0) | 2023.08.02 |
[C#] 고급문법_람다식 (0) | 2023.07.31 |