Thread 사용하면서 자원공유는 쉬운 문제가 아니다.

예를 들어 txt를 많은 Thread가 동시에 사용한다면 충돌을 피하기 어렵다. 

 

일반적인 파일 입출력 예

using (FileStream Fs = new FileStream(filePath, FileMode.Append))

                { 

                    StreamWriter streamWriter = new StreamWriter(Fs, Encoding.UTF8); 

                    streamWriter.Write("Something...\n"); 

                    streamWriter.Close(); 

                    emailResertFs.Close(); 

                } 

Thread가 아니면 문제가 되지 않는 코드이지만 Thread면 문제가 달라진다.

 

저 코드가 일반적인 상황이 아닌 Thread를 사용하면서  Thread가 위의 코드를 처리한다고 가정하자. 

 

운이 좋으면 지나가겠지만 그렇지 않으면 위와 같은 에러를 만나게 된다. 

원인은 두개 이상의 Thread가 동시에 txt파일에 액세스 하려고 하면서 발생하는 문제이다. 

 

이 문제를 간단히 해결해보자 

 

해결책 - lock 사용 

 

위의 예제를 이렇게 바꿔보자 

 

private object locker = new object(); //맴버변수로 위에서 따로 정의한다. 




 lock (locker) 

            { 

                using (FileStream Fs = new FileStream(filePath, FileMode.Append))

                { 

                    StreamWriter streamWriter = new StreamWriter(Fs, Encoding.UTF8); 

                    streamWriter.Write("Something...\n"); 

                    streamWriter.Close(); 

                    emailResertFs.Close(); 

                } 

            } 

lock 키워드는 블록 안에 있는 코드를 한 Thread에서만 사용할 수 있게 해주는 키워드이다.

블록에 있는 코드가 끝나기 전까지는 다른 Thread가 들어오지 못한다.

lock()의 파라미터는 임의의 객체를 사용할  있지만 일반적으로 private object 형태로 만든다. 

 

Lock(obj) 

{ 

	Do Something; 

} 

특별한 상황이 아니라면 이렇게 만들자.

 

참고

여기에서 만약에 클래스 객체인 this를 사용하여 lock(this)라고 하면 의도치 않게 데드락이 발생될 수 있기 때문에 this는 사용하지 않는 것이 좋다. 

 

this를 사용하면 집을 잠그는 개념이고 obj를 사용하면 방문을 잠그는 개념. 

집을 lock해야 하는 경우도 있기 때문에 무조건 사용하지 않는 것은 아니지만 일반적으로는 방만 lock하자! 

 

마지막으로 코드 블록 ( { } 사이 코드 )  범위는 최대한 작게 하는 것이 좋다. 

 

결론 

 

대소문자 구분 

EndsWith(".png");

 

대소문자 구분 안함 

EndsWith(".jpg", true, null);

 

2번째 인자가 true이면 구분 안함, false이면 구분함.

 

설명 

 

c#에서 확장자를 다룰 때 EndsWith() 사용하는 경우가 있다. 

 

Directory.GetFiles(_rootPath, "*.*", SearchOption.AllDirectories).Where(s => s.EndsWith(".jpg", true, null) || s.EndsWith(".png"));

Directory.GetFiles(_rootPath, "*.*", SearchOption.AllDirectories).Where(s => s.EndsWith(".jpg", true, null) || s.EndsWith(".png")); 

 

이런식으로.. 

RootPath에서부터 하위 폴더까지 파일을 검색할 때 위와 같이 많이 사용하는데 

모든 파일을 보는 것이 아니라 특정 확장자만 봐야 하는 경우가 일반적이다. 

 

이럴 때 Where와 EndsWith를 함께 사용하는데 이럴 때 확장자가 대소문자 구분을 하지 말아야 할 때가 많은데 예제와 같이 작성하면 확장자를 구분한다. 

 

 

참고 : https://docs.microsoft.com/ko-kr/dotnet/api/system.string.endswith?view=netcore-3.1#System_String_EndsWith_System_String_ 

 

EndsWith를 사용하는 방식은 총 4 가지이다. 

이 중 4번째 방식을 사용하면 된다. 

 

 

 

코드를 작성하다 보면 문자열에 공백문자가 들어갈 때가 있다. 

C#에서는 간단히 제거할  있고 Trim이  역할을 해준다. 

<코드>

string st = "\r\n \t 문자열 입니다 \n ";
Console.WriteLine(st);
Console.WriteLine("===================");
Console.WriteLine("|" + st.Trim() + "|");

 

<결과>

 

위와 같이 문자열의 앞/뒤 공백문자를 제거해준다. 

 

Trim() - 문자열의 앞 뒤 공백문자 제거

TrimStart() - 문자열의 앞 공백문자 제거

TrimEnd() - 문자열의 뒤 공백문자 제거

 

참고로 중간에 있는 공백문자는 제거하지 않는다. 

제거하고 싶다면 Replace나 정규식의 치환 등을 이용하면 된다. 

 

+ Recent posts