벌레잡이 시리즈 (1) 간단한 프로그램부터 라인 보안
4744 단어 스레드 보안
PS 한 번: 아래 댓글을 보면 벌레의 뜻을 오해하고 있습니다. 이 시리즈의 블로그는 벌레를 잡는 데 목적을 두고 있습니다. 벌레를 잡는 과정에서 우리 프로그램에 쉽게 발생하는 문제를 주목하는 것이지 더 좋은 해결 방안을 찾는 것이 아닙니다. 헤헤~
원본 버그 프로그램을 먼저 보십시오
class testObj
{
public object Result { get; set; }
public int index { get; set; }
}
public void Test()
{
ManualResetEvent[] MR = new ManualResetEvent[20];
testObj qq = new testObj();
for (int i = 0; i < 20; i++)
{
MR[i] = new ManualResetEvent(false);
qq.index = i;
ThreadPool.QueueUserWorkItem(o =>
{
Console.WriteLine(qq.index.ToString());
MR[qq.index].Set();
}, qq);
}
WaitHandle.WaitAll(MR);
}
우리의 목적은 프로그램이 0~19까지 출력하도록 하는 것이다.여기를 보니 늙은 새가 프로그램의 문제를 발견했나 봐요.새 새는 벌레를 계속 조사해야 한다.늙은 새들이 먼저 뜸을 들여 벌레가 문제를 빗나가게 하면 더욱 많은 문제를 넓힐 수 있다.운행 결과를 봅시다.
그때 깜짝 놀랐는데..벌레가 엉뚱한 생각을 하기 시작했어. 왜 그랬을까?스택 문제?그래, 창고를 공고히 해라. 값 유형은 창고에 있고, 값 유형의 복사는 깊은 복사이다. 우리가 값 유형의 파라미터를 전달할 때 창고에 새로운 공간이 분배되고, 이 파라미터의 값은 이 공간에 복사된다.이런 현상은 일어나지 않겠지.아니야!!!int는testObj에 봉인되었습니다. 인용 형식은 얕은 복사입니다.오, My Girl Friend, 발견했어!이 스무 개의 스레드는 같은 복사본을 사용하는데...벌레가 뭐하는 거야. 스무 개의 스레드로 하여금 같은 데이터를 동시에 조작하게 해.
이것은 문제다.위에서 말한 것은 문제지만 이 현상이 발생한 유일한 문제가 아니냐는 것이다.이 비동기 프로그램에서, 라인이 대상 자원을 가져올 때, for 순환의 주 라인에서 이미 다 뛰었다.그래서 qq의 index는 줄곧 20입니다.여기까지 읽으면 아마도 몇몇 늙은 새들은 이미 코웃음을 치기 시작했을 것이다. 이런 잘못은 그들이 범하지 않을 것이다.원인을 알게 되면 우리는 해결 방안을 분석하러 올 것이다.한 층 한 층 벗기고,
우선 이 패치 01번 프로그램을 보시죠.
public void Test()
{
ManualResetEvent[] MR = new ManualResetEvent[20];
EventWaitHandle EH = new AutoResetEvent(false);
testObj qq = new testObj();
EH.Set();
for (int i = 0; i < 20; i++)
{
MR[i] = new ManualResetEvent(false);
qq.index = i;
EH.WaitOne();
ThreadPool.QueueUserWorkItem(o =>
{
Console.WriteLine(qq.index.ToString());
MR[qq.index].Set();
EH.Set();
}, qq);
}
WaitHandle.WaitAll(MR);
}
AutoReset Event 가 추가되었으며 이는 자동 Reset 이벤트 알림 방식입니다.여러분이 자주 사용하는 통금 시스템에 해당한다고 형상적으로 말했다.처음에wait상태였는데, 누군가가 set을 해야만 통과할 수 있습니다.이것은 라인을 하나하나 제어하는 데 쓰인다. 즉, 매번 대상이 한 사람만 접근할 수 있다는 것이다.이제 우리 라인은 안전하겠지, 하하하하.효과도를 다시 보다.
신마!!!많이 좋아진 것 같은데 1, 1, 19, 19를 반복하는 게 얼마나 불협화음이야.그래, 계속 벌레를 잡아라.(⊙o⊙)...또 주선이 출입문에 통제되었지만 주선과 이보선의 리듬이 다르다는 것을 발견했다. 운이 좋으면 네가 낸 결과가 맞을 수도 있다.근데 메인 라인은 처음에 패스가 떨어졌을 수도 있는데 첫 번째 비동기 라인은 아직 안 끝났어요.⊙o⊙...벌레가 우리를 속이는 이 방안은 근본적으로 이 문제를 해결하는 것이 아니다. 우리의 문제는 우리의 프로그램이 같은 자원 qq를 사용했다는 데 있다.
들켰어!!!
그래, 수리 02번 프로그램은 아래와 같다.
public void Test()
{
ManualResetEvent[] MR = new ManualResetEvent[20];
testObj qq = new testObj();
for (int i = 0; i < 20; i++)
{
qq = new testObj();
MR[i] = new ManualResetEvent(false);
qq.index = i;
ThreadPool.QueueUserWorkItem(o =>
{
Console.WriteLine(qq.index.ToString());
MR[qq.index].Set();
}, qq);
}
WaitHandle.WaitAll(MR);
}
길게 한숨을 쉬니 이제 문제 없겠지.헤헤, 이번에는 내가 모든 라인에 하나의 대상을 독립적으로 분배할 수 있어.사실이 이러한가?늙은 새들이 몰래 웃기 시작했을 거야. 효과도를 봐.
╮╯ 너 또 흔들렸어. 이 문제의 관건은 네 번째 줄에 있어. 네가 형성한 모든 것은 독립된 자원인 것 같아. 사실 너는 좀 부주의했어.
아래 에서 방안 을 바로 이해하였다
public class cnBlog
{
public void Test()
{
ManualResetEvent[] MR = new ManualResetEvent[20];
for (int i = 0; i < 20; i++)
{
testObj qq = new testObj();
MR[i] = new ManualResetEvent(false);
qq.index = i;
ThreadPool.QueueUserWorkItem(o =>
{
Console.WriteLine(qq.index.ToString());
MR[qq.index].Set();
}, qq);
}
WaitHandle.WaitAll(MR);
}
}
이전의 방안과 한 줄의 프로그램을 다른 곳으로 바꿨을 뿐이지만 의미가 완전히 바뀌었다. 진정한 결과가 어떤지 보자.
oh yeah~ 서열이 좋지 않지만 정상!
퀴즈는 그만하고 벌레잡이가 여러분에게 보잘것없는 수확을 가져다 주었으면 좋겠습니다.