메뉴 건너뛰기

넷서버 사용 팁/강좌

사용팁 DLL과 Deadlock

admin 2008.01.20 06:52 조회 수 : 6347

스레드에서 DLL을 사용할 경우 Deadlock이 발생할 가능성이 높다는 것은  여러 디버깅책에서 나왔습니다.
하나의 해결책을 제시한 ng 아티클입니다.

No, the dll does not pass or export strings so sharemem should not be
>necessary.
>
>In experimenting with this problem, I've stripped it down to its simplest
>components: a thread unit that defines a thread that just calls messagebeep
>every two seconds, a main unit that creates and frees the thread in its
>initialization and finalization sections and defines a procedure that starts
>the thread, a dll project that exports the main units procedure, and a
>simple app that loads the dll dynamically and hooks the dll's procedure to a
>button event so that the thread can be started.

I believe your basic problem is that you're running into this Windows
restriction (from the documentation of ExitProcess and ExitThread):

  Only one thread in a process can be in a DLL initialization or detach
  routine at a time.

The unit finalizations within the DLL take place during the handling of a
DLL_PROCESS_DETACH in the context of the main thread. The finalization tells
the thread to quit and waits for it. The thread's state, however, will not
become signaled until all DLL thread detach routines have been executed in the
context of the terminating thread. However, (because of the above restriction)
since the main thread is still in its process detach routine, the terminating
thread has to wait for it to return before it can execute its detach routines.
Result: deadlock.

By the way, I was able to produce the deadlock with an even more minimal set up
than you used. I had a console app consisting of LoadLibrary/FreeLibrary and a
DLL which used BeginThread and this thread proc:

var Finished: boolean = false;

function ThreadProc(P: pointer): integer;
begin
  repeat
    Sleep(1000);
  until Finished;
  Result:= 0;
end;

{... to the DllProc}
  DLL_PROCESS_DETACH:
    Finished:= true;
    if ThreadH <> 0 then
      WaitforSingleObject(ThreadH, INFINITE);
{...}



>
>If I start the thread and then close the app and use the series of
>statements outlined in my initial post to kill the
>thread, the calling app will hang in the waitfor function of classes.pas and
>never shutdown.
>If I use Peter's suggestion and set FreeOnTerminate
>the app will close properly, but this solution does not work with my "real"
>project. It cause AV's. It also does not work with an experimental case
>where multiple threads are created. Again AV's result. This leads me to
>believe that there is a timing problem.

Using FreeonTerminate allows the DLL_PROCESS_DETACH routine to complete, but it
then proceeds to call the routine with DLL_THREAD_DETACH. Having
DLL_PROCESS_DETACH run before DLL_THREAD_DETACH is no doubt a recipe for AV's.
Among other things, the heap manager is uninitialized during the finalization
(in DLL_PROCESS_DETACH) of the system unit.

Basically, you have to figure out some way to make sure that DLL_PROCESS_DETACH
does not execute until all the threads are terminated. One way to do this would
be for each thread to call LoadLibrary on your DLL when they start, and then
call FreeLibrary when they terminate (this is the idea behind the API function
FreeLibraryAndExitThread). That way, the DLL will not actually be unloaded
until the last thread terminates.

But that means you have to have some way of telling the threads when to
terminate. If the idea is to terminate when the application does, you might set
up a windows hook to check for the destruction of the application's main window,
and use that as a signal to destroy the threads.

Finally, I think there is one small bug in the VCL's DLL thread implementation:
during the processing of DLL_THREAD_DETACH, ExitThreadTLS is called before
DllProc (this happens in the _StartLib procedure in system.pas; the code with
the comment "Init any needed TLS" will call one of InitProcessTLS, InitThreadTLS
or ExitThreadTLS depending on the DLL_XXXX parameter. ExitProcessTLS is
correctly called after DllProc and unit finalizations). ExitThreadTLS calls
LocalFree on the thread's local storage. This means that a DllProc which tries
to access a threadvar will be accessing a block of memory which has been
Local-freed. Whether that will inevitably lead to AV's I don't know.

Good luck,

Greg Chapman

번호 제목 글쓴이 날짜 조회 수
공지 이전게시판의 질문과답변 및 사용팁 메뉴얼관련 링크 admin 2008.01.23 4633
공지 넷서버 동영상 강좌 admin 2008.01.23 3915
공지 넷서버 소개문서 넷서버 2008.01.19 5110
31 midaslib를 추가해 주십시오 admin 2015.08.19 285
30 XE2 이후 unit scope table admin 2014.02.28 24183
29 Java 1.6버젼과 windows server 2008 r2 문제 admin 2011.12.13 3954
28 넷서버 에러코드 및 설명 admin 2011.06.04 5060
27 윈도우서버 2008 R2에서의 닷넷의 문제 admin 2010.05.27 33553
26 패키지의 설치시 폴더의 설정 admin 2009.03.17 49313
25 XP모드에서 TPanel의 Color 사용방법 admin 2008.05.23 4466
24 FibPlus에서 Boolean 필드사용방법 admin 2008.03.18 11541
23 SQLite의 사용상의 주의 admin 2008.02.28 4379
22 디버그컴포넌트(MaxExcept, EurekaLog...)의 사용시 유의사항 admin 2008.02.16 5296
21 Open Source ODBC DBX Driver admin 2008.02.05 3398
20 넷서버의 설치 방법 admin 2008.01.24 4873
19 [동영상] 넷서버 클라이언트 프로그램의 제작 admin 2008.01.24 3035
18 [동영상] 넷서버 서버의 제작 admin 2008.01.24 2700
17 Ch7. 채팅클라이언트 프로그램의 제작 admin 2008.01.24 3176
16 Ch6. 채팅서버 프로그램의 제작 admin 2008.01.24 3116
15 ch 5. 비즈니스오브젝트를 클라이언트에서 사용하기 admin 2008.01.24 2722
14 ch 4. 비즈니스오브젝트의 작성-서버 admin 2008.01.24 4479
13 ch 3.메세지클라이언트의 제작 admin 2008.01.24 4526
12 ch 2. 간단한 클라이언트프로그램의 제작 admin 2008.01.24 2988
위로