방금 내 코드의 어느 곳에서 잠금 내부와 외부에 return 문이 있음을 깨달았습니다. 어느 것이 최고입니까?
1)
void example()
{
lock (mutex)
{
//...
}
return myData;
}
2)
void example()
{
lock (mutex)
{
//...
return myData;
}
}
어느 것을 사용해야합니까?
방금 내 코드의 어느 곳에서 잠금 내부와 외부에 return 문이 있음을 깨달았습니다. 어느 것이 최고입니까?
1)
void example()
{
lock (mutex)
{
//...
}
return myData;
}
2)
void example()
{
lock (mutex)
{
//...
return myData;
}
}
어느 것을 사용해야합니까?
답변:
기본적으로 코드가 단순 해집니다. 단일 종료 지점은 이상적이지만, 코드를 달성하기 위해 코드를 구부리지 않을 것입니다 ... 그리고 대안이 로컬 변수 (잠금 외부)를 선언하고 초기화하면 (잠금 내부) 그런 다음 (잠금 외부에) 반환하면 잠금 내부의 간단한 "반환 foo"가 훨씬 간단하다고 말하고 싶습니다.
IL의 차이점을 보여주기 위해 다음과 같이 코드를 작성하십시오.
static class Program
{
static void Main() { }
static readonly object sync = new object();
static int GetValue() { return 5; }
static int ReturnInside()
{
lock (sync)
{
return GetValue();
}
}
static int ReturnOutside()
{
int val;
lock (sync)
{
val = GetValue();
}
return val;
}
}
(나는 그것이 ReturnInside
더 간단하고 깨끗한 C # 비트 라고 행복하게 주장 할 것 입니다)
그리고 IL (릴리스 모드 등)을보십시오.
.method private hidebysig static int32 ReturnInside() cil managed
{
.maxstack 2
.locals init (
[0] int32 CS$1$0000,
[1] object CS$2$0001)
L_0000: ldsfld object Program::sync
L_0005: dup
L_0006: stloc.1
L_0007: call void [mscorlib]System.Threading.Monitor::Enter(object)
L_000c: call int32 Program::GetValue()
L_0011: stloc.0
L_0012: leave.s L_001b
L_0014: ldloc.1
L_0015: call void [mscorlib]System.Threading.Monitor::Exit(object)
L_001a: endfinally
L_001b: ldloc.0
L_001c: ret
.try L_000c to L_0014 finally handler L_0014 to L_001b
}
method private hidebysig static int32 ReturnOutside() cil managed
{
.maxstack 2
.locals init (
[0] int32 val,
[1] object CS$2$0000)
L_0000: ldsfld object Program::sync
L_0005: dup
L_0006: stloc.1
L_0007: call void [mscorlib]System.Threading.Monitor::Enter(object)
L_000c: call int32 Program::GetValue()
L_0011: stloc.0
L_0012: leave.s L_001b
L_0014: ldloc.1
L_0015: call void [mscorlib]System.Threading.Monitor::Exit(object)
L_001a: endfinally
L_001b: ldloc.0
L_001c: ret
.try L_000c to L_0014 finally handler L_0014 to L_001b
}
IL 수준에서 그것들은 (이름을 지어 주거나) 동일합니다 (나는 무언가를 배웠습니다 ;-p). 따라서 유일하게 현명한 비교는 지역 코딩 스타일의 (매우 주관적인) 법칙입니다 ... 나는 ReturnInside
단순성을 선호 하지만 어느 쪽도 흥분하지 않을 것입니다.
ret
.try
아무런 차이가 없습니다. 둘 다 컴파일러에 의해 동일한 것으로 번역됩니다.
명확히하기 위해 다음 의미를 가진 것으로 효과적으로 변환됩니다.
T myData;
Monitor.Enter(mutex)
try
{
myData= // something
}
finally
{
Monitor.Exit(mutex);
}
return myData;
나는 확실히 반품을 자물쇠 안에 넣을 것이다. 그렇지 않으면 다른 스레드가 잠금을 입력하고 return 문 전에 변수를 수정하여 원래 호출자가 예상과 다른 값을 받도록 할 수 있습니다.
때에 따라 다르지,
나는 곡물에 반대 할 것입니다. 나는 일반적으로 자물쇠 안쪽으로 돌아갑니다.
일반적으로 변수 mydata는 지역 변수입니다. 로컬 변수를 초기화하는 동안 선언하는 것을 좋아합니다. 내 자물쇠 밖에서 반환 값을 초기화 할 데이터가 거의 없습니다.
따라서 비교에는 실제로 결함이 있습니다. 이상적으로 두 옵션의 차이점은 당신이 작성한 것과 같을 것입니다. 사례 1에 끄덕이는 것은 실제로 조금 더 추합니다.
void example() {
int myData;
lock (foo) {
myData = ...;
}
return myData
}
vs.
void example() {
lock (foo) {
return ...;
}
}
특히 짧은 스 니펫의 경우 사례 2가 읽기 쉽고 조이기 어렵다는 것을 알았습니다.
참고 : 나는이 답변이 사실 정확하다고 생각하며 도움이되기를 바랍니다. 그러나 구체적인 피드백을 바탕으로 항상 개선 해 드리겠습니다.
기존 답변을 요약하고 보완하려면 :
허용 응답 에 관계없이 어떤 문법 형태의 당신이 당신의 선택, 쇼 C #을 런타임에 따라서 그리고 - - (가) 일리노이 코드, 코드 return
때까지 발생하지 않습니다 후 잠금이 해제됩니다.
return
내부lock
부정확하게에게, 제어 흐름 엄밀히 말하면 블록 따라서 [1] , 이는 문법적이고 편리한 그것이 AUX에 반환 값을 저장할 필요성을 제거하는 것이있다. 지역 변수 (블록 외부와 함께 사용할 수 있도록 블록 외부에 선언 return
) -Edward KMETT의 답변을 참조하십시오 .별도로 - 그리고 이러한 측면은 부수적 질문에,하지만 여전히 (관심을 가질 수있는 리카르도 Villamil의 대답의 시도가 그것을 해결하기 위해,하지만 잘못, 내 생각) - 합성 lock
로 문을 return
문 - 즉, 가치를 획득 return
로부터 보호 블록에 동시 액세스- 일단 획득 한 후 실제로 보호 할 필요가없는 경우 호출자 의 범위 에서 반환 된 값을 의미있게 "보호"하는 것은 다음 시나리오에 적용됩니다.
반환 값이 컬렉션 의 요소 인 경우 요소 자체 의 수정 및 / 또는 요소가 아닌 요소 추가 및 제거 측면에서만 보호가 필요한 경우 ...
... 값은 인스턴스 인 경우에 반환되는 값 유형 또는 스트링 .
다른 경우 에는 메서드 내부가 아닌 호출자 가 잠금을 수행해야합니다 .
[1] 테오도르 Zoulias은 그 기술적 또한 사실 배치하는 것이 지적 return
내부 try
, catch
, using
, if
, while
, for
, ... 문; 그러나, lock
이 질문이 요청되어 많은 관심을 받았음에 따라, 진정한 통제 흐름에 대한 조사를 요구할 가능성 이있는 진술 의 구체적인 목적이다 .
[2] 값 유형 인스턴스에 액세스하면 스레드 로컬의 스택 사본이 생성됩니다. 문자열은 기술적으로 참조 형 인스턴스이지만 값과 유사한 유형의 인스턴스처럼 효과적으로 동작합니다.
lock
있으며 return 문을 배치하여 의미를 도출하고 있습니다. 이 질문 IMHO와 관련이없는 토론은 어느 것입니까? 또한 나는 사용법을 발견 "misrepresents" 상당히 혼란 스럽습니다. A로부터 복귀하면 lock
부정확하게 제어의 흐름을 한 후 동일한가 돌아가는 상기 수 try
, catch
, using
, if
, while
, for
, 및 임의의 다른 언어 구조. C #에 제어 흐름 오류 표시가 수수께끼라는 말과 같습니다. 예수 ...
try
, if
... 나는 개인적으로 그것에 대해 생각하는 경향이 없지만,의 맥락에서 lock
특히, 문제는 나를 위해 발생 -와 너무 다른 사람을 위해 발생하지 않은 경우,이 질문은 질문하지 않았을 것이다 승인 된 답변은 실제 행동을 조사하기 위해 많은 시간이 걸리지 않았습니다.