none
C# 병렬처리 질문입니다 ! ( 질문 그림 포함! ) RRS feed

  • 질문

  •  

     

    위의 그림을 슬쩍 설명을 하자면 , Thread_1 에서 비트맵을 생성을 하였습니다. 그리고 생성이 완료 된후

    각 쓰레드가 완성된 비트맵을 이용하여 출력을 하는건데, 멀티스레드 환경에서 안정적으로 접근하기 위해

    lock(bitmap){ ... } 처럼 접근을 하였습니다.  

    그런데 이것은 먼저 접근한 스레드의 비트맵 읽기가 완료되면 다음 쓰레드로 가는 방식이어서 (? 맞죠 ?ㅎ )

    진정한 의미의 병렬 처리가 될수 없음을 생각하였습니다.

    그리고 lock(bitmap){...} 을 쓰지 않으면 산발적으로 에러가 나더군요 ,

    그리고 정말 방법이 없을까 , 하고 생각하던 도중 의문이 들었습니다.

     

    상식적으로 비트맵을 만들고 있는 도중에 접근 한다는것은 당연히 에러를 내밷는게 맞지만

    이미 완료된 데이터를 동시에 여러객체가 읽는것이 어쩌면 가능하다는 생각이 들었습니다 .

    그림을 그려보면 이렇게 될것 같은데요 ,

     

     

     

     

    위의 그림처럼 비트맵이 완성되고 각각의 스레드에서 객체1 , 객체2 , 객체3 이 동시에 비트맵에 접근하는것인데요 ,

    이런 생각이 가능한 생각일까요 ?

     

    고수님들의 도움이 필요한 시점! 입니다 .ㅎ

    귀찮으시더라도 .. 키워드 쯤이라도 떤져 주세요 ..

     

     

    2011년 1월 24일 월요일 오전 7:14

답변

  • 또 뵙네요. :)

    설명 하는데 사용하신 그림은 직접 그리신건가요~? 실력이 부럽습니다.

     

    우선 질문하신 내용에 대해서 개인적인 답변을 드리겠습니다.(정답이 아닐 수 잇다는 거죠-_-)

    lock을 거는 이유는 알고 계시겠지만, 한 스레드가 데이터를 읽는 도중에 다른 스레드가 값을 변경시킬 경우에 예상치 못한 결과가 발생하기 때문입니다. 그래서 값을 변경시킬 우려가 없는 상황이라면, 즉 읽기만 하는 상황이라면 lock은 걸지 않아도 상관없습니다.

    하지만, 만약에 읽으시려는 비트맵이 메모리에 존재하는게 아니라 파일등의 점유가 필요한 곳에 존재한다면 lock이 필요하겠죠.

    간단하게 여러 스레드가 동시에 한 데이터를 읽는 코드를 작성해봤습니다. 여기서는 Task클래스를 사용하고 있는데요, Task클래스는 .NET 4에서 추가된 클래스로 TPL(Task Parallel Library)의 기본이 되는 클래스이며 내부적으로는 ThreadPool 클래스를 통해서 스레드 풀링을 구현하고 있습니다.

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;

    namespace ConsoleApplication1
    {
        class Program
        {
            const int maxIndex = 10000000;
            static int[] mainArray = new int[maxIndex];

            static void ReadArrays()
            {
                Console.WriteLine("{0}, 작업 시작!"Task.CurrentId);

                int[] localArray = new int[maxIndex];

                for (int i = 0; i < mainArray.Length; i++)
                {
                    localArray[i] = mainArray[i];
                }

                Console.WriteLine("{0}, 작업 끗!"Task.CurrentId);
            }

            static void Main(string[] args)
            {
                Task mainThread = new Task(
                    () =>
                    {
                        for (int i = 0; i < mainArray.Length; i++)
                        {
                            mainArray[i] = i + 1;
                        }
                    });

                mainThread.Start();

                Task[] threads = new Task[]
                {
                    new Task(() => ReadArrays()),
                    new Task(() => ReadArrays()),
                    new Task(() => ReadArrays()),
                    new Task(() => ReadArrays())
                };

                mainThread.Wait();

                for (int i = 0; i < threads.Length; i++)
                {
                    threads[i].Start();
                }

                Task.WaitAll(threads);
            }
        }
    }

    2코어 2.0Ghz인 제 컴퓨터에서 위 코드를 실행해보면, 매번 다르긴 하지만 대략 아래와 같은 결과가 나옵니다.

    1, 작업 시작!
    2, 작업 시작!
    2, 작업 끗!
    3, 작업 시작!
    1, 작업 끗!
    4, 작업 시작!
    3, 작업 끗!
    4, 작업 끗!
    계속하려면 아무 키나 누르십시오 . . .

    물론 배열의 크기가 좀 더 작은 경우에는 순차적으로 끝나는 모습을 보여주지만, 메모리에 존재하는 걸 사용하는 거라면 위와 같은 코드로 동시에 접근하는 것도 가능합니다.

    부족한 실력으로 답변드리는데 도움이 되셨으면 좋겠군요 :)

    • 답변으로 표시됨 야매코더 2011년 1월 24일 월요일 오후 3:57
    2011년 1월 24일 월요일 오후 12:32

모든 응답

  • 또 뵙네요. :)

    설명 하는데 사용하신 그림은 직접 그리신건가요~? 실력이 부럽습니다.

     

    우선 질문하신 내용에 대해서 개인적인 답변을 드리겠습니다.(정답이 아닐 수 잇다는 거죠-_-)

    lock을 거는 이유는 알고 계시겠지만, 한 스레드가 데이터를 읽는 도중에 다른 스레드가 값을 변경시킬 경우에 예상치 못한 결과가 발생하기 때문입니다. 그래서 값을 변경시킬 우려가 없는 상황이라면, 즉 읽기만 하는 상황이라면 lock은 걸지 않아도 상관없습니다.

    하지만, 만약에 읽으시려는 비트맵이 메모리에 존재하는게 아니라 파일등의 점유가 필요한 곳에 존재한다면 lock이 필요하겠죠.

    간단하게 여러 스레드가 동시에 한 데이터를 읽는 코드를 작성해봤습니다. 여기서는 Task클래스를 사용하고 있는데요, Task클래스는 .NET 4에서 추가된 클래스로 TPL(Task Parallel Library)의 기본이 되는 클래스이며 내부적으로는 ThreadPool 클래스를 통해서 스레드 풀링을 구현하고 있습니다.

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;

    namespace ConsoleApplication1
    {
        class Program
        {
            const int maxIndex = 10000000;
            static int[] mainArray = new int[maxIndex];

            static void ReadArrays()
            {
                Console.WriteLine("{0}, 작업 시작!"Task.CurrentId);

                int[] localArray = new int[maxIndex];

                for (int i = 0; i < mainArray.Length; i++)
                {
                    localArray[i] = mainArray[i];
                }

                Console.WriteLine("{0}, 작업 끗!"Task.CurrentId);
            }

            static void Main(string[] args)
            {
                Task mainThread = new Task(
                    () =>
                    {
                        for (int i = 0; i < mainArray.Length; i++)
                        {
                            mainArray[i] = i + 1;
                        }
                    });

                mainThread.Start();

                Task[] threads = new Task[]
                {
                    new Task(() => ReadArrays()),
                    new Task(() => ReadArrays()),
                    new Task(() => ReadArrays()),
                    new Task(() => ReadArrays())
                };

                mainThread.Wait();

                for (int i = 0; i < threads.Length; i++)
                {
                    threads[i].Start();
                }

                Task.WaitAll(threads);
            }
        }
    }

    2코어 2.0Ghz인 제 컴퓨터에서 위 코드를 실행해보면, 매번 다르긴 하지만 대략 아래와 같은 결과가 나옵니다.

    1, 작업 시작!
    2, 작업 시작!
    2, 작업 끗!
    3, 작업 시작!
    1, 작업 끗!
    4, 작업 시작!
    3, 작업 끗!
    4, 작업 끗!
    계속하려면 아무 키나 누르십시오 . . .

    물론 배열의 크기가 좀 더 작은 경우에는 순차적으로 끝나는 모습을 보여주지만, 메모리에 존재하는 걸 사용하는 거라면 위와 같은 코드로 동시에 접근하는 것도 가능합니다.

    부족한 실력으로 답변드리는데 도움이 되셨으면 좋겠군요 :)

    • 답변으로 표시됨 야매코더 2011년 1월 24일 월요일 오후 3:57
    2011년 1월 24일 월요일 오후 12:32
  • 헠 . 놀랍습니다 . 아직 테스트는 못해봤지만 .슬쩍 검색 해봤는데 , TPL 이거 .. 완전 신세계네요 , 우와 .. 더불어 PLINQ 라는것도 이제서야 이해 했습니다.

    이거 완전 잘해봐야 할것 같습니다 ! 공부쫌 해보고 , 포스팅해야겠어요!

     

    그나저나 너무 답변 잘 달아주셔서 , 뭐 어찌 고마움을 표시해야 할지 = =;;;

    사실 궁금한게 자꾸 자꾸 생겨서, ....  또 물어 봐도 되죠 ? ㅎㅎ ( 자꾸 받아먹기만 해서 ..ㅋㅋ )

    2011년 1월 24일 월요일 오후 4:03