내 머리로는 이해가 안되고
검색도 어떻게 해야할지 한참 고민하다
마땅한게 검색어가 안 떠올라서 질문해 횽들
까놓고 말해서 과제중인데
멀티 스레드 프로그램 중 발생할 문제들 있잖아
그런 문제에 관한 건데
과제를 해결하는 과정중에 내 머리로는 동작이 이해가 안되는게 있어서 질문해
일단 슈도코드를 적자면
공유변수=0;
특정한횟수 = 임의의숫자;
메인 스레드()
{
스레드1 생성
for(특정한횟수 만큼순회)
{
공유변수++;
}
}
스레드1종료기다림;
공유변수 출력;
}
스레드1()
{
for(특정한횟수 만큼순회 )
{
공유변수++;
}
}
}
대충 이런데 공유변수의 최종 값이 특정한횟수*1 이상 특정한횟수*2 미만이 되는 상황이 제일 이상적이겠지??
(그니까 실제 코딩상황에서는 공유변수 사용할 때 저런식으로 발생하면 안되겠지만
그냥 공유변수를 스레드에서 동시 접근이 일어났을때를 설명하기위한 이상적인 상황을 말하는거야)
그러한 결과를 출력해서 설명하려고 했는데
이해가 정확히 안가는 상황이 뭐냐면
일단
1. 공유변수의 최종값이 특정한횟수*2가 나오는 경우
=> 이건 뭐 어떻게 스레드 1이 실행이 시작되기 전에 메인 스레드 안의 루프가 끝나버리면 되니까 이건 뭐 어느정도 이해
2. 공유변수의 최종값이 특정한횟수*1이 나오는 경우
=> 이 경우가 어떻게 해도 이해가 안돼
2번 경우는 사실상 특정한 횟수가 1000000번이라고 치면
전부 더해졌을때 2000000이 나와야 하는 상황에서 1000000이 나왔다는 얘긴데
그럼 각각의 스레드가 각각의 루프를 각각 만회씩 수행을 하는 과정에서
컨텍스트 스위칭이 정확히 공유변수가 메모리에서 레지스터로 로드되는 시점에만 1000000회가 일어난다는 이야기인데
이게 말이 되나?
근데 웃긴게 여러모로 테스트 해봤는데 특정한 횟수가 1억 이상 넘어가면
그런 현상이 없고, 1000~5000만회 정도면 그런경우가 많이 없는데 그래도 조금 발생하고
1000만회 이하는 매우 자주 발생했고
근데 내가 문득 드는 생각이, 내가 위 코드를 노트북(싱글코어)에서 돌려본거거든
그래서 동일한 컴파일러로 듀얼코어인 PC에서 돌려보면 결과가 다를까? 해서 돌려봤는데 노트북이랑은 달리 특이한 경우는 확 줄어들었고
노트북에서 돌렸을때랑은 달리 노트북에서는 만회정도 돌렸을때는 거의 고정으로 10000, 아님 20000이 나오고
한 단위가 천만이상, 즉 충분히 커야
십만이상회 가면 적어도 내가 여러본 돌리는 확률정도로는 위에서 말한 특이케이스 안나오더라고.
당연하다면 당연한 얘기같은데 단일cpu에서는 위의 코드중에 스레드 생성후 스위칭이 안된상태에서 수행을 끝내버려서 그랬겠지;
근데 그렇다 하더라도 2번의 경우는 이해가 잘 안되서..
아 그리고, 그냥 혹시나 증가되는 과정에 문제가 있나 싶어서 노트북으로 테스트할때
개별 변수를 각각의 루프에 부여해서 루프내부에서 증가시킨후에 출력하는 것도 추가시켜봤는데
그런 개별 변수를 넣은 이후에는 또 정상적으로 작동을 하더라고 ㅡ,.ㅡ
아무튼 내가 말을 잘 못씨부려서
안읽은 횽들도 있겠지만
읽어준 횽들 고마웤ㅋ
스레드 1 돌기전에 메인스레드가 죽는경우
스레드1 시작하려고 막 준비하고 있는데 메인스레드는 이미 포문 다 돌고 출력도하고 끝?, 어? 메인이 끝났어!
전나 말도 안되지만 메인하고 스레드1이 공유변수를 번갈아가면서 증가 시킬때
increase 는 한 단위처럼 보이지만 tmp 에다가 대입, 원래 변수를 증가시키고, tmp 를 되돌려주는 과정
메인 스레드가 tmpM = 1 을 넣은 뒤 스레드 스위칭 되고 , 스레드 A가 tmpA = 1 을 넣게 되면 뭐 그냥 한번 증가한거나 마찬가지
ㅋㄱ// ㅋㄱ횽 위의 슈도코드에는 언급 안됐는데 스레드1에서 루프가 끝난 후에 최종적으로 어떤 전역 변수를 1로 수정하고 메인스레드에서 그 전역변수가 1일때까지 while루프를 무한히 돌다가 1이되면 비로소 확인하고 출력을 하는 부분이 있거든 근데도 메인스레드가 먼저 끝날 수 있으려나? 한번 확인은 해볼게 고마워 ㅋ
메인스레드에서 \'스레드1을 기다림\' 이게 원래 스레드 라이브러리로는 join 하는 거임, 메인스레드는 스레드 1이 끝나길 반드시 기다리니까 항상 스레드 1은 전부 돌게 됨
[성대아싸] // 성대아싸횽 나두 그생각 했는데 한 100만회정도 수행될동안 정확히 똑같은 위치에서 스위칭이 되서 결과적으로 양쪽에서 100만회 증가시켰는데 최종적으로 한 110-120만회 정도 증가됐다고 하면 그럴수도 있을것같은데, 최종적으로 100만, 즉 한쪽 루프는 거의 수행되지 않은것처럼 보일 수도 있는거야?
↑ 댓글은 위에 댓글에 대한 답변 ㅋ
근데 말이다, 크리티컬 섹션은 넣어보고 해보면 다를 것 같은데
(그럼 그럴일은 없을듯ㅋ\')
ㅁㄴㄻㄹ// ㅁㄴㄻㄹ횽 어떤게 다를것 같다는 이야기야?
INCREASE 가 어셈블리 레벨에서 투 스텝으로 이루어졌다고 가정하면, 1. 임시값에 원래 값을 넣는다 2. 원래 값을 한개 증가시킴
ㅋㄱ// 음 그런가 ㅋ 암튼 고마워 횽 ㅋㅋ
정 궁금하면 전체코드를 한번 올려보렴. 당연 개별변수 쓰면 횽이 말한대로 되지
근데 존나 말도 안되지만 메인스레드가 공유변수 1값을 가지고 스텝1을 수행함, 그리고 스텝 2로 가기전에 스위칭됨 , 그러면 스레드1 입장에서도 아직 공유변수가 증가하지 않은 거임, 이새끼도 공유변수를 1로 읽고 스텝 1을 수행함, 그리고 스위칭됨
그제서야 쓰기연산이 들어가는데 메인스레드나 , 스레드 1이나 똑같이 공유변수 값을 1로 읽어왔었기 때문에 증가시켜봤자 둘다 똑같은 값이 됨, 그러니까 정확하게 두 스텝 한가운데서 (쓰기연산 일어나기 직전) 번갈아가면서 스위칭 되는 조또 말도 안되는 경우
성대아싸 // 그런데 그것이 실제로 일어났습니다 인가?ㅋㅋㅋ 그거밖에 없는것 같지?
그나저나 슈도코드 보고 지림,,,, 패기 쩌네요
아 원래 그렇게 의심하고 있었구나 ,,, 근데 실제로 테스트 하면 스위칭 인터벌은 적어도 명령어 수백개는 실행하고 나서야
일광면 // 질문 올린것부터 좀 찔리긴 한데,과제인지라 혹시나 차후에 문제가 생길까봐(머 별일은 없겠지만) 일부러 슈도코드로 올렸엌ㅋ
글 지우기만 해봐라 간만에 댓글 존나 쌋는데 불안하다
[성대아싸]// 음 그럼 뭘까 ..ㅋㅋ 아오 그냥 내일 노트북 들고 교수님한테 가서 직접 물어봐야하나
ㅋㅋㅋㅋㅋㅋ 지우진 않을게 먹튀는 안함
야 그럼 말을 그렇게 해야지.. 그래야지 쓸데없는 괴변을 안늘려놓지 --;
아무튼 답변 달아준 성대아싸횽 일광면횽 ㅋㄱ횽 ㅁㄴㄻㄹ형 고맙구여 고민좀 더해보다 안되면 드랍.. 이아니라 교수님한테 찾아가서 질문을 ㅇㅇ..
일광면 // 횽 미안요 ㅜㅜㅋ
아 자러가야겠다 그냥 ㅡㅡ; 도와준 횽님들 감사합니다. 자러갑니다
위의 슈도코드에서 공유변수 액세스시에 동기화 처리를 하지 않으면 결과값을 정의할수 없는 프로세스가 됩니다. 변수 액세스 코드는 atomic 연산이 아니기에 여러개의 머신코드를 생성하고(실제론 2~3개정도), 그 코드사이에 쓰레드 스위칭이 발생합니다. 하지만 웬만한 장비에서 1백만번 돌릴동안 이러한 상황이 발생할 확률은 많아 봤자 수십개 내외 입니다.
2와 같은 결과가 나온 이유는 쓰레드 생성후 해당 쓰레드가 휴면상태에서 활동상태로 전이 하기까지 오래 걸린 경우 임으로, 보다 정확한 테스트는 동기화 처리를 하여 두개의 루프가 동시에 시작하도록 하는겁니다. 그러면 2백만개 - (수개~수십개) 정도의 결과가 나올겁니다.
공유변수 액세스시 동기화 처리를 하면 결과는 항상 1과 같이 나오도록 보장됩니다. 동기화 처리를 하지 않은 위의 슈도코드는 아무런 의미가 없는 코드입니다.
동기화는 어떻게 하나요? 늅늅
동기화 기능은 운영체제에서 보통 제공해줍니다. 윈도우즈(유닉스,리눅스도 비슷함) 의 경우라면 쓰레드 및 프로세스간 동기화를 위해 크리티컬 섹션, 뮤텍스, 세마포어 등을 제공합니다. 자세한건 win32 관련자료로서 msdn이나 api 정복(가남사) 같은 문서를 참고하시면 됩니다.