Q&A

  • Fucn1 이라는 시리얼 출력 함수를 쓰레드와 일반호출에서 동시 사용한다면...

---**쓰레드와  메이폼 버튼 클릭시 사용될 공용 시리얼 출력함수

procedure Tfrom1.Func1(str : string);
begin
  with Query1,Query1.SQL do
  begin
     Close;Clear;
     Add('select remark from contents where aaa = '''+str'''');
     Open;
     while not eof do  // while loop가 50회 정도된다면...
     begin  
        Comport.WriteStr( fieldbyname('remark').AsString);
        Next;
     end;
  end;
end;


--** 쓰레드에서시 호출하는 루틴

procedure TMyThread.Execute;
begin
  while (not Terminated)  do begin
    try
      Msg := from1.Client1.ReadLn;
      if Length(Msg) >= 1 then begin
         Synchronize(Func1('Msg'));
    except
      Terminate;
    end;
  end;
end;



---**메인 폼에서 버튼클릭시 Func1 사용하는 루틴

procedure Tfrom1.button1Click(sender :Tobject);
begin
   Func1('Y');
end;




안녕하세요~

시리얼로 출력을 하는 public 함수 "Func1" 을 쓰레드에서

Synchronize 로 동기화 하여 호출 사용하고

메인폼에서 버튼을 클릭하면 역시 "Func1"  사용할수 있는 환경에서...



쓰레드에서 Func1 호출하여 50회 정도 루프를 돌면서 시리얼로 text를 전송하고 있는 도중에

메인폼에서 버튼을 클릭하여 역시 50회 돌면서 text 를

전송하면 상호 간섭이 발생되지 않을까요?


예를 들면 쓰레드에서 호출한 Func1이 50회를 돌면서  1 ~ 50 까지 숫자를 출력 도중에

난데없이 메인에서 Func1  호출하여 51 ~ 100 까지 숫자

출력호출하면

출력 결과가  1~30 까지 나오고 다음에 51~100까지 나오고

그다음에 31 ~ 50 까지 출력 되는 어이 없는 경우가 발생되지는 않는지?..


물론 1-50까지 출력은 아주 짧은 시간내에 출력이 되기 때문에
별 문제없이 출력 됩니다마는 만약 굉장히 긴 Loop를 돌고 있다면

혹시 상호 간섭으로 섞여 나올수 있을수도 있게다 싶어 여러분들의

조언을 듣고 싶습니다.

만약 이상없이 출력 된다면 혹은 섞여서 출력 되는

문제가 발생되는지 그 원리가 아주 아주 궁금합니다.

4  COMMENTS
  • Profile
    최용일 2006.03.31 19:59
    안녕하세요. 최용일입니다.

    말씀하신대로 상호간섭이 발생합니다.

    이걸 막으실려면 Critical Section같은것을 이용하세요.

    ^^ 항상 즐코하세요.

  • Profile
    델파이-델짱 2006.03.31 23:19
    답변 감사 드립니다.^^;

    시리얼 영수증 출력기로 Test해보았는데
    재미있는 결과가 나오네요^^;

    ------------Func_1;--------------------------
    if 쓰레드호출이면
      str := 'AAAAAAAAAAAAAAAAAAAAAAAA'
    else if 메인버튼호출이면
      str := 'ZZZZZZZZZZZZZZZZZZZZZZZZ';

    i :=0;
    while i < 100 do begin
       inc(i);
       Comport.WriteStr(str);
    end;
    ------------------------------------------------
    --**먼저 쓰레드로 Func_1 호출하여 시리얼로 출력요청하고
    쓰레드에서 출력을 완료하기 전에

    메인버튼에서 버튼을 눌러  Func_1  함수를 호출해서
    출력 요청했을경우 즉 동시 출력 요청인 경우...

    출력결과는 쓰레드에서 요청한 100라인 먼저 출력되고
    메인함수에서 출력 요청한 100라인이 순서대로
    잘 출력 됩니다 . 그리고 LOOP수를 200 , 300회 돌려도
    아주 정상적으로 출력이됩니다.



    --**동일한 방법으로 While Loop안에
    application.Processmessages; 넣고
    Test하니 다른 결과나 나오네요

    결과는 쓰레드에서 요청한 50라인정도 먼저 출력되고
    버튼클릭으로 요청한 100라인이 출력 되고
    마지막에 쓰레드에서 요청한 결과가 나오네요

    우려했던 섞여서 출력 되는 결과가 나오네요.

    TEST 해본 결과로 유추해보면 LOOP속에
    Application.Processmessage만 넣지 않으면
    문제가 없는것처럼 판단 됩니다.


    혹 Critical Section 을 사용안해도 될까요?
    아니면 운영체제에따라 다른 결과가 나올수 있을까요?

    Critical Section 을 사용하려면 출력루틴을 모두 함수화 해야
    해야 되는것으로 알고 있습니다.
    그런데 현재 프로젝트에서 시리얼출력 부분이 너무 많아 함수화
    하기가 곤란해서 Critical Section 사용하기가
    조금 어렵습니다.

    감사합니다


  • Profile
    하얀까마귀 2006.04.01 04:35
    안녕하세요 하얀까마귀 입니다.

    오랜만에 답변을 쓰네요..

    결론부터 말씀드리면 안써도 될것 같습니다만.. 쓰는것이 더 좋습니다.

    말씀하신 프로젝트 내에서는 꼭 써야할 필요는 없을듯 하네요 하지만 이것은 어디까지나 제가 님이 만드신 프로그램을 제대로 알지 못하고 하는 말이고 제가 그 프로젝트를 분석한다면 다른 말을 할지도 모르죠..

    쓰레드 내의 문제가 간단하다면 ( 예로든것처럼. ) 안써도 될듯 합니다..

    일단 님이 테스트하신 결과에 대해서 설명을 드리면..

    아시겠지만 쓰레드 라는건 프로그램내에서의 작업단위입니다. os에서 cpu가 처리하는 구분이기도 하구요.

    해당 쓰레드만큼 작업이 돌아가는거죠..

    제가 알고 있는걸로는.. 쉽게 말해서 하나의 쓰레드에서 하나의 함수를 기준으로 돌아간다고 보시면 될듯 하네요 정확하게 일치하지는 않지만 대충 이렇다고 보면 될듯 합니다.

    즉.. 님이 테스트한 버튼클릭을 누르는순간 쓰레드의 작업은 멈추고 해당 버튼의 루프가 돌아가게 됩니다.

    따라서 중복이 일어나지 않겠죠?  당연히 중복은 일어나지 않을껍니다.

    그런데 중간에 피크메세지 아니 processmessage를 넣어주면 이놈을 부르는순간 해당 부분에서 처리를 기다리는 다른 작업들을 처리하게 됩니다.

    음.. peekMessage라고 api함수인데.. 현재 대기중인 메세지를 가져와서 처리하도록 되어있는 겁니다.

    좀 여러가지로 쓰이는건데 ㅎㅎ..

    따라서 저 함수를 불러주는 순간 쓰레드가 돌겠죠? 당연히 중복될수 밖에는 없습니다.

    원칙적으로 쓰레드의 개념을 시간적인 개념으로 생각하는게 가장쉽죠.. 각각의 쓰레드가 시간단위로 분할되면 가장 좋겟지만 이렇진 윈도우즈는 이렇게는 하지 않는걸로 알고 있습니다.. 쓰레드의 작업처리하는것도 방식이 많습니다.

    그럼 그냥해도 크리티컬세션 안써도 될것 같은데.. 문제는 님이나 저나 해당 프로젝트에서 사용한 함수들 콤포넌트들에 대해서 100% 알지 못한다는거죠.. 알지 못하는 버그가 존재할 가능성이 높습니다. 따라서 그냥 맘편히 쓰레드 쓸때는 충돌이 일어날수 있을만한곳은 넣어주는게 좋죠..

    하지만 지금은 그냥 콤 통신이고 ( 콤 콤포넌트는 한번 살펴보시는게 좋겠죠? ) 이런경우 굳이 사용하지 않아도 무방해 보입니다.

    대부분 크리티컬세션은 변수를 위해서 사용합니다..  음.. 글이좀 길어지는것 같은데.. 예를들면

    <!--CodeS-->
    procedure TestThread.Execute;
    begin
      while not terminated do
      begin
        WriteComport;
        sleep(100);
      end;
    end;

    procedure TestThread.WriteComport;
    begin
      Inc ( aNum );
      WaitForSingleObject( self.Handle, DelayTime );
      print_aNum; // aNum값 출력
    end;

    <!--CodeE->

    Delaytime 은 외부에서 받는다고 하고 aNum은 전역변수라고 하죠

    이렇게 TestThread를 여러개 만들면 출력되는 aNum 이 순차적이지 않을껍니다.

    1번쓰레드가 anum을 증가시키고 WaitForSingleObject( self.Handle, DelayTime ); 여기서 대기하는동안
    2번 쓰레드가 다시 aNum값을 증가시킬수 있으니까요 이 쓰레드가 서너개가 되면 더하겠죠?

    간단한 방법은  Synchronize 이놈을 쓰는겁니다. 함수를 프로시져로 만들었으니..


    <!--CodeS-->
    procedure TestThread.Execute;
    begin
      while not terminated do
      begin
        Synchronize( WriteComport ); // 이렇게 고칩니다
        sleep(100);
      end;
    end;
    <!--CodeE->

    이렇게 고칩니다. 이렇게 하면 여러개의 쓰레드에서 writecomport 라는 함수를 동시에 들아기지 못합니다.

    즉 1번 쓰레드가 실행하고 있으면 2,3번 쓰레드는 대기합니다. 음. 효율적이진 않겠죠? 따라서 저런함수는 아주 심플하게 만들어야 됩니다.

    문제는 anum 이라는 변수를 이렇게 하면 쓰레드 내부에서는 해결된것 같은데.. 외부에서 변경하는건 해결이 안됩니다.  외부에서도 anum이라는 변수를 수정한다면 문제가 될수 있겠죠?

    원하는데로 동작을 안할수도 있을껍니다...

    이런경우 TCriticalSection 을 만들어서 써주면 됩니다...

    -----  고치기 전 코드는 아마 출력값이 1,1,2,3,4,4,5,5,6,7,8,9,10,10 뭐 이런식으로 중복된 숫자가 나오지 않을까 싶네요..   Synchronize 이걸 쓴거는 1,2,3,4,5,6 으로 잘나오겠지만 문제는 속도면에서 저하가 있겠군요.. 대기를 저 함수내부에 있으니.. 물론 원래는 이딴식으로 쓰레드 만들면 안되겠죠 ㅎㅎ

    마지막으로 Synchronize 를 빼버리고 TCriticalsection을 쓴다면 변수를 변경하는부분을 try finally로 묶어서 써주면 되겠습니다.. 물론 anum을 변경하는 모든 부분에 같은 cs를 해줘야 겠죠? 그럼.

    쓰레드에 대해서 잘 아시겟지만 제 나름대로 하나도 모르신다고생각하고 적다보니 좀 길어졌네요 ㅎㅎ

    그럼 모자라는 지식이나마 도움이 되셧기를..

    그럼 초보 하얀까마귀






  • Profile
    델파이-델짱 2006.04.01 20:49
    • 가시나무 새
      2006.04.01 03:09
      델마당 강좌 팁에서 보고 해보니 되는군요 아래와 같이 해보시길   wb.Navigate('ht...
    • 박성준
      2006.04.01 19:09
      안녕하세요? 박성준입니다. 일전에 웹브라우저에서 반복작업을 수행하는 간단한 매크로 프로그램(Macro Pr...
    • 신철우
      2006.04.01 18:55
      감사합니다. FormCreate에는 안되고 FormShow에 하니까 됩니다.
    • 가시나무 새
      2006.04.01 04:05
      델마당에서 검색해서 Test 해보니 되네요 .. procedure TForm1.GetWebImage(AImageURL: String); var ...
    • 신철우
      2006.04.01 19:47
      uses에 JPEG, idHTTP를 해야하는데 idHTTP는 Indy Clients에서 생성하면 5개 Component가 한꺼번에 만들어...
    • 가시나무 새
      2006.04.01 19:55
      HTTP := TIdHTTP.Create(Self); 이부분이 있으니 Indy Clients 를 따로 내려놓지 않으셔도 될듯해요 .. ^...
    • 레도
    • 2006.03.31 20:36
    • 2 COMMENTS
    • /
    • 0 LIKES
    • 최용일
      2006.03.31 20:43
      안녕하세요. 최용일입니다. 이벤트에 파라매터로 들어오는 Sender가 이벤트를 발생한놈이니까 이걸 참조...
    • 레도
      2006.03.31 21:10
      오옷..  깔끔하게 잘 됩니다. 감사합니다. 개념을 잡지 못해 고생했는데, 이렇게 쉽게 되는...
    • 멍멍이
    • 2006.03.31 20:00
    • 1 COMMENTS
    • /
    • 0 LIKES
    • 김현학
      2006.04.21 20:30
      방법 처럼 Edit라는 명령을 이용하시면 될것구요 DB에 Index가 있으면 Findkey라는 명령이 있구요 아...
    • 최용일
      2006.03.31 19:59
      안녕하세요. 최용일입니다. 말씀하신대로 상호간섭이 발생합니다. 이걸 막으실려면 Critical Section...
    • 델파이-델짱
      2006.03.31 23:19
      답변 감사 드립니다.^^; 시리얼 영수증 출력기로 Test해보았는데 재미있는 결과가 나오네요^^; ---...
    • 하얀까마귀
      2006.04.01 04:35
      안녕하세요 하얀까마귀 입니다. 오랜만에 답변을 쓰네요.. 결론부터 말씀드리면 안써도 될것 같습니...
    • 델파이-델짱
      2006.04.01 20:49
    • [ROOKIE]
      2006.03.31 19:31
      <!--CodeS--> function TListItems.AddItem(Item: TListItem; Index: Integer): TListItem; begin ...
    • 이은주
      2006.04.13 09:30
      답변글을 뒤늦게 봤습니다. 답변해 주셔서 감사합니다.
    • 마르
      2006.03.31 20:06
      웹페이지 내용을 긁어와서 데이터를 가공하는건 굳이 어플리케이션을 이용할 필요는 없습니다. 실시간으...
    • 문의득
    • 2006.03.31 02:14
    • 8 COMMENTS
    • /
    • 0 LIKES
    • 최용일
      2006.03.31 02:27
    • 문의득
      2006.03.31 03:01
    • 최용일
      2006.03.31 03:05
    • 문의득
      2006.03.31 03:21
    • 최용일
      2006.03.31 03:45
    • 문의득
      2006.03.31 04:29
    • 최용일
      2006.03.31 04:46
    • • • •
    • 박종철
    • 2006.03.31 02:00
    • 2 COMMENTS
    • /
    • 0 LIKES
    • 최용일
      2006.03.31 02:29
      안녕하세요. 최용일입니다. idFTP1.Get이 수행되면서 Caption을 표시할 여유가 없어서 발생하는 문제같...
    • 박종철
      2006.03.31 02:42
      아 정말 감사합니다... ^^ 이것때문에 정말 답답했었는데.. 답변도 이렇게 빨리 올려주시다니.... 즐...
    • 박해성
    • 2006.03.30 20:38
    • 0 COMMENTS
    • /
    • 0 LIKES
    • 박성준
    • 2006.03.30 19:16
    • 2 COMMENTS
    • /
    • 0 LIKES
    • 이영화
      2006.03.30 22:36
      하하 뜻을 굽히지 않으셨군요. non-marker(표식을 달지 않은? 마킹되지 않은?) 대립형질(유전자)의 해석...
    • 박성준
      2006.03.31 02:28
      답변감사드립니다. 그런데 중요한게 생겼어요. marker-based란 내용을 찾아야 되는데 인터넷 아...
    • 이경희
    • 2006.03.30 05:52
    • 0 COMMENTS
    • /
    • 0 LIKES
    • 이영화
      2006.03.30 22:22
      "쿼리문" 이랑 "쿼리문을 뺀 문장" 을 소켓 프로그램이 구분할 것 같지는 않네요. 데이타 타입이 틀리거나...
    • 델티즌
      2006.03.30 10:01
      에러 문을 보지 않아서....참고적으로 몇자 적습니다. 서버에서는 슬레드로 처리하시는게 건강상 좋습니다...
    • 희아빠
      2006.04.07 22:04
      감사합니다..... 답변을 보고도 이제야 감사의 글을 드리내요 ^^ 관심에 감사드립니다,
    • 탁선호
    • 2006.03.30 01:12
    • 1 COMMENTS
    • /
    • 0 LIKES
    • 탁선호
      2006.04.04 00:04
      아래 부분을 했더만 잘 되던데요... MemStream.WRITE(lpbImage^,sizeof(lpbImage)); lpbImage 끝에 ^...
    • 이재영
    • 2006.03.29 20:48
    • 2 COMMENTS
    • /
    • 0 LIKES
    • 박성훈
      2006.03.29 20:56
      장사집인가 보네요.  포스용 프린터를 쓰시는 걸 보니... 그 넘을 이용해서 출력하는 방법...
    • 이재영
      2006.03.30 03:53
      아이고 감사합니다. 아니 이모가 갈비집하는데 좀 도와 달라고 해서 허접하게 흉내내어 봤는데..ㅋㅋ 사...
    • 테러
      2006.03.30 01:54
      Crystal Report 9.x대 버전에서는 Delphi 7.0까지 지원되는 VCL이 공급이 되는것 같습니다. 아마 Cty...
    • 강중규
      2006.03.30 02:45
      아 그렇군요. 그러면 폴더의 위차와 파일명이 어떻게 되죠.
    • 테러
      2006.03.30 02:50
      탐색기에서 VCL로 검색하면 있었던것 같은데 그 이상은 잘몰겠습니다.
    • 깔쌈보이
      2006.03.29 19:21
      룩업콤보박스에 연연하시면 안되구요... KeyValue를 알 수가 있으니까... KeyValue를 가지고 룩업테이...
    • 김병윤
      2006.03.30 02:45
      말씀처럼 룩업콤보박스에 연연하지 않기로 했습니다. 좀 깔끔하게 해결되었으면 했는데..^^;; 입력되는 ...