2011-12-20 3 views
12

나는 경우이 : 다른와 DoSomething멀티 스레딩 및 .NET에서 폐쇄

public string DoSomething(string arg) 
{ 
    string someVar = arg; 
    DoStuffThatMightTakeAWhile(); 
    return SomeControl.Invoke(new Func<string>(() => someVar)); 
} 

그리고이 방법은 여러 스레드에서 동시에 호출 할 수 있으며, 하나 개의 스레드는 DoStuffThatMightTakeAWhile에 갇혀 한 다음 두 번째 스레드 호출 arg이면 모든 스레드에 대해 someVar의 값이 변경되므로 DoSomething은 두 번째 호출에서 someArg의 두 번째 버전을 반환하거나 각 스레드에 대해 하나의 someVar이 존재합니까?

ActionFunc이어야한다고 생각합니다.

답변

16

가에 혼란이 될 것입니다. 여기서 답은 지역 변수가 "스레드의 스택에"할당된다는 허위 사실을 기반으로합니다. th 거짓 및 부적절한.

로컬 변수가 일부 임시 풀이나 장기 저장 풀에 할당 될 수 있으므로 false입니다. 임시 풀에 할당 되더라도 스택 메모리 일 필요는 없습니다. 그것은 레지스터가 될 수 있습니다. 저장 장치가 할당 된 풀이 누가 누가 있기 때문에 상관이 없습니까?

메서드 활성화마다 최상위 로컬 변수가 할당됩니다. 일반적으로 블록의 로컬 변수는 입력되는 블록 당 한 번 할당됩니다. 예를 들어, 루프 본문에 선언 된 지역 변수는 루프가 돌아갈 때마다 할당됩니다.

자, 질문을 생각해 보자 :

이 방법은 여러 스레드에서 동시에 호출 할 수 있습니다.한 스레드가 DoStuffThatMightTakeAWhile에 멈춘 상태에서 두 번째 스레드가 다른 arg로 DoSomething을 호출하면이 작업으로 모든 스레드의 someVar 값이 변경됩니까?

번호 해봐요의 각 활성화에 대한 새로운 "의 somevar"가있다.

각 스레드마다 하나의 someVar가 있습니까?

에 대해 하나의 "someVar"가 존재합니다. 스레드가 정확히 하나의 활성화를 수행하면 스레드 당 정확히 하나의 someVar가있게됩니다. 스레드가 백만 번 정품 인증을 수행하면 백만 개가 실행됩니다. 둘 다 읽기 및 로컬 변수를 기록 대리자를 만들 경우, 당신은 여러 스레드, 다음 모든 정품 인증 위임주의 밖으로 대리자 손 : 말했다

, 존 한나의 대답은 정확 동일한 지역 변수. 마법 쓰레드 안전이 만들어지지 않습니다. 원한다면 스레드 안전을 보장 할 책임이 있습니다.

+0

그래서'string myVar; '와 같은 선언은'new' 키워드로 객체를 생성하는 것처럼'myVar'를 __create__ 할 것입니까? 이것은 재귀 호출에도 적용됩니까 ('DoSomething'이'DoSomething'을 호출 할 경우)? – Juan

+2

@jsoldi : 메모리 할당자가 새 지역을 만드는 방법과 객체에 대한 새로운 저장소를 만드는 방법은 배경에서 매우 다를 수 있지만 개념적으로는 동일합니다. 그리고 예, 재귀 호출은 * 재귀 호출과 같은 * 활성화 *입니다. 모든 * 활성화 *는 새로운 지역 주민을 얻습니다. –

+1

왜 이것을 "메소드 호출"이 아닌 "메소드 활성화"라고 부르는가? 이것은 특별한 용어입니까? – Restuta

7

로컬 변수는 현재 스레드의 스택에 저장되므로 각 스레드는 고유 한 스택을 가지며 각 변수에는 someVar 변수가 포함됩니다. 그것은 각 스레드에서 다른 값 것 때문에

new Action(() => someVar)); 

someVar의 자신의 가치의 캡처합니다. 에릭은 지적

편집 나는 그 말을 단순히 잘못이었다. 정확한 설명을 위해 그의 대답을보십시오.

+1

"현재 변수의 스택에 현재 로컬 변수가 저장되어 있습니다"라고 잘못되었습니다. 클로저에서 캡처 된 변수는 힙에 할당됩니다. –

+0

Jason이 맞습니다. 이 답변에는 그 안에 확실한 논리가 없습니다. –

+0

그래, 내 잘못, 난 내 대답을 수정하지 않습니다, 당신의 하나가 완벽하게 좋다. – Restuta

1

마찬가지로, DoSomething을 타격하는 각 스레드는 스택에 별도의 someVar을 생성하므로 다른 스레드가 다른 스레드에 영향을 미치지 않습니다. someVar

로컬이 클로저에서 캡처되고 해당 범위에서 멀티 스레딩이 시작된 경우 이는 서로 다른 스레드가 실제로 볼 수있는 값에 영향을 미칠 수 있다는 점에 유의해야합니다. 우리가 일반적으로 다른 방법에 영향을 줄 수 있습니다로하지 뭔가 생각 치 형 (- 폐쇄가 클래스 메소드와는 다르다 이런 식으로 :

public static void Main(string[] args) 
{ 
    int x = 0; 
    new Thread(() => {while(x != 100){Console.WriteLine(x);}}).Start(); 
    for(int i = 0; i != 100; ++i) 
    { 
     x = i; 
     Thread.Sleep(10); 
    } 
    x = 100; 
    Console.ReadLine(); 
} 

시연이

+0

올바르게 이해했다면, 모든 스레드가 액세스하는 단 하나의'x' (메인 스레드에서 생성 된 하나) 만 존재합니까? – Juan

+0

바로, 수동으로 생성 된 스레드는 주 스레드가 스레드를 증가시키는 동안 콘솔에 계속 쓰게됩니다. –

+1

someVar는 처음부터 스택에 할당되지 않습니다. 휴면 오버 지역은 수명이 연장되므로 힙에 할당됩니다. –