linux에서 thread사용에 대해

리눅스에서 pthread_create를 하면 fork가 되죠.
리눅스 장비에서 thread를 create시킨 후 pstree utility로 살펴보면
parent process의 boss thread(최소의 thread)에서 일단 중간단계의
process를 하나 생성한 후 생성된 process에서 실제로 thread의 역활을 하
게 될 process를 생성하는 것을 확인 할 수 있습니다.
그리하여 process에서 thread를 n개 생성시켰다면 실제로는 n+2개의
process가 pstree에 잡히는 것을 볼 수 있습니다.
이와 같은 현상때문에 porting할 때 문제가 생기기도 하죠.
문제는 뭐냐면....
unix계열의 process에서는 thread1, thread2를 생성한 다음에 다른 모든
thread(parent포함)에서 SIGTERM을 block한 이후 sleep하고 있고 thread1
에서만 SIGTERM에 대해 sigwait을 하고 있는 상태에서 parent process에
게 SIGTERM을 날리면 thread1이 실행이 됩니다.
그런데 unix에서는 thread를 create하면 말 그대로 thread가 생기지만
linux에서는 process가 fork가 되기 땜시 문제가 발생하는데......
linux의 process에서 thread1, thread2를 생성한 다음에(fork가 되지
만....) 모든 thread(parent포함)는 SIGTERM에 대해 block한 이후 sleep하
고 있고 thread1에서만 SIGTERM에 대해 sigwait을 하고 있는 상태에서
parent process에게 SIGTERM을 날리면 꿈쩍도 안 합니다.
이 때 pstree로 보면 pthread_create를 call한 이후 process에서는 중간단
계의 process를 하나 생성한 후 그 process에서 thread의 역활을 할
process를 생성하는 것 같았습니다.
그래서 process에서 thread를 두개를 생성시켰는데 급기야는 4개의
process가 pstree에 잡히는데 parent에게 SIGTERM을 날려도 다른 thread에
게 그것을 전달하지 않는 것 같았습니다. 단 sigwait에 block되어 있는
thread(process이지만)에게 SIGTERM을 직접 날리면 원하는 바대로 동작을
합니다.
이와 같은 경우를 목격하게 되어서 찾아본 결과 clone이라는 것에 대해 알
게되었는데....
clone 역시 process를 fork하는 system call이지만 parent process와
file descriptor table이나 signal handler나 memory를 공유할 수 있더라
구요.
그래서 위와 같은 경우를 해결하기 위해서는 pthread_create대신
CLONE_GIGHAND를 set하여서 clone을 호출하면 해결할 수 있을 듯 합니다.
혹은 process가 thread로 생성되는 다른 경우의 문제점도 clone을 사용하
여 풀 수 있는 걸로 보입니다.
지금부터 질문인데요......
unix에서 linux로 포팅하면서 컴파일에 대한 문제는 없었고요. 리눅스 특
유의 thread를 만드는 방식때문에 signal handler를 parent와 child가 공
유하지 못하여서 sigwait이 의도한 바대로 동작하지 않는 문제가 생기는데
그래서 소스를 thread_create()에서 clone()으로 대치하여야만 parent와
child가 signal handler를 공유하는 가에 대한 의문을 여쭈어 보고 싶습니
다.
unix에서 linux로 multi-thread app를 porting할 때에는 소스를 하나도 건
드리지 않을 수 없다라고 생각하는데.... 아닌가... 아는 게 별
로 없어서.... 그에 대한 답변도 부탁드립니다.
Re: 리눅스에서 쓰레드 구현과, 쓰레드와 시그널
리눅스 쓰레드 구현은 clone으로 구현이 됩니다.
LinuxThreads provides kernel-level threads each thread is a separate
Unix process, sharing its address space with the other threads through
the new system call clone(). Scheduling between threads is handled by
the kernel scheduler, just like scheduling between Unix processes.
arch/i386/kernel/process.c
asmlinkage int sys_clone(struct pt_regs regs)
{
unsigned long clone_flags;
unsigned long newsp;
clone_flags = regs.ebx;
newsp = regs.ecx;
if (!newsp)
newsp = regs.esp;
return do_fork(clone_flags, newsp, ®s, 0);
}
kernel/fork.c에서 do_fork부분의 소스를 보면
각 상황별로 clone_flags를 가지고 다니면서, 처리가 이루어집니다.
리눅스가 이런 구조를 지니는 것은 기존의 구조를 변경을 최소화 하면서
쓰레드 기능을 구현을 하다보니.. 이렇게 된것이죠..
그리고 쓰레드를 사용하면
메인프로세스+쓰레드메니져 +쓰레드(1)...쓰레드(n) = N +2 란 공식이 나오게 되는데
이것은 제가 예전에 답글을 단적이 있으니 아래의 링크를 참조하세요
http//kldp.org/script/bbs/read.php?table=qa2&no=3628
쓰레드에서 시그널 문제는...
linuxthreads library의 README에 언급이 잘되어 있습니다.
http//pauillac.inria.fr/~xleroy/linuxthreads/README
- The current implementation uses the two signals SIGUSR1 and SIGUSR2,
so user-level code cannot employ them. Ideally, there should be two
signals reserved for this library. One signal is used for restarting
threads blocked on mutexes or conditions; the other is for thread
cancellation.
- Signal handling does not fully conform to the Posix standard,
due to the fact that threads are here distinct processes that can be
sent signals individually, so there's no notion of sending a signal
to "the" process (the collection of all threads).
More precisely, here is a summary of the standard requirements
and how they are met by the implementation
1- Synchronous signals (generated by the thread execution, e.g. SIGFPE)
are delivered to the thread that raised them.
(OK.)
2- A fatal asynchronous signal terminates all threads in the process.
(OK. The thread manager notices when a thread dies on a signal
and kills all other threads with the same signal.)
3- An asynchronous signal will be delivered to one of the threads
of the program which does not block the signal (it is unspecified which).
(No, the signal is delivered to the thread it's been sent to,
based on the pid of the thread. If that thread is currently
blocking the signal, the signal remains pending.)
4- The signal will be delivered to at most one thread.
(OK, except for signals generated from the terminal or sent to
the process group, which will be delivered to all threads.)
또, LinuxThreads Frequently Asked Questions 에서도
시그널에 대한 언급과 리눅스 쓰레드 내부구현에 관현 이야기가
잘 언급되어 있습니다.
http//pauillac.inria.fr/~xleroy/linuxthreads/faq.html#A
J. Signals and threads
J.1 When it comes to signals, what is shared between threads and what isn't?
J.2 When I send a SIGKILL to a particular thread using pthread_kill,
all my threads are killed!
J.3 I've installed a handler on a signal. Which thread executes the
handler when the signal is received?
J.3 How shall I go about mixing signals and threads in my program?
J.4 When one thread is blocked in sigwait(), other threads no
longer receive the signals sigwait() is waiting for! What happens?
K. Internals of LinuxThreads
K.1 What is the implementation model for LinuxThreads?
K.2 Have you considered other implementation models?
twopairs님께서 질문한 내용에 대한 답을 얻을려면
위에 언급한 내용을 모두 읽어보시고,.. 그래도 이해가 안되는 부분을
다시 질문해 주세요..
지금의 질문은 답을 하기전에 알려드려야 할 사항이 너무 많아서
힘드네요.. ^^ 하지만,
쓰레드에서 시그널 핸들링을 위한 문제는 쓰레드 라이브러리
개발 초부터 많은 논의가 있어서 찾아보시면 답이 있습니다.
Re^2: 감사합니다. ^^
좋은 정보 주셔서 감사합니다.
매우 궁금한 사항이었는데... 찾질 못해서 답답했었었네요.
다시 한번 감사드리고...
하루하루 좋은 일만 있으시길 바랄께요. ^^
Linux thread에서 SIGUSR1, SIGUSR2 사용에 대하여...
http://pauillac.inria.fr/~xleroy/linuxthreads/README
이 문서를 보면 다음과 같은 내용이 있습니다.
테스트 해보니... signal()이나 sigaction()으로 SIGUSR1과 SIGUSR2를 설정하고 mutex lock을 획득하려하거나 condition을 wait하는 thread에게 pthread_kill()로 SIGUSR1이나 SIGUSR2를 보내면 아무 일도 발생하지 않았고, mutex lock/unlock과 condition 발생에 영향을 미치지 않는것으로 보였습니다.
정상적으로 mutex lock을 획득할 때나 condition 이 발생할 때도 signal이 발생하는 것을 감지할 수는 없었구요.
문서의 내용이 지금에는 맞지 않는 것인지.. 어떻게들 생각하시나요?
그리고... 결국 Linux에서 phread 사용 시에 thread간에 SIGUSR1과 SIGUSR2 약속하고 사용해도 상관이 없을까요?
테스트 결과로 보면 user-code에서 SIGUSR1과 USR2의 사용이 thread library내부의 mutex, condition variable이나 thread cancellation 에 영향을 미치지 않는것으로 보이고, 그래서 사용하는 것도 상관없어 보이는데... 문서에 저렇게 나와있으니 확신이 안가는군요.
의견 부탁합니다.
우리 모두 리얼리스트가 되자. 그러나 가슴에 이룰 수 없는 꿈을 가지자
기존의 리눅스쓰레드는 시그널 처리에 있어서는 POSIX 호환이 아
때문에 호환을 원하시면 NPTL이나 NGPT를 사용하셔야할 것입니다. 일단 NGPT는 개발이 중단 되었으니 NPTL을 사용하셔야 할 듯 합니다. 이문제는 커널 2.6이 나오면 완전히 해결이 되겠지만 현재는 커널과 GLibC에 패치를 하고 사용을 하셔야 합니다.
예... 답변 감사합니다.호환을 전제하지 않는다면 어떨까요?
예... 답변 감사합니다.
호환을 전제하지 않는다면 어떨까요?
user-code에서 SIGUSR1, USR2를 사용해도 문제는 없는걸까요?
우리 모두 리얼리스트가 되자. 그러나 가슴에 이룰 수 없는 꿈을 가지자
문서에 있는 것처럼...
아마 사용을 피하시는 것이 좋을 것이라 생각됩니다만 그 목적이 Reserve된 것과 같다면 별 문제가 있겠습니까?(무책임... :-)
결국 지금의 LinuxThread 에서는 thread간에 signal을
결국 지금의 LinuxThread 에서는 thread간에 signal을 약속하고 사용해서는 안된다는 말씀이신것 같군요.
정말 그럴까요?
좀 당황스럽군요.
우리 모두 리얼리스트가 되자. 그러나 가슴에 이룰 수 없는 꿈을 가지자
여기 와서 많은걸 배우고 있네요 ^^;[code:1]On ``ol
여기 와서 많은걸 배우고 있네요 ^^;
커널2.2이후로는 사용가능하다는 이야기 같은데..
그리고 코드 안에서 bold체가 안먹는군요 T.T
그나저나 백수 언제 탈출하냐... ㅡㅡ; 배고파라.
아... 답변 감사합니다.동일한 사이트에 README에는 upda
아... 답변 감사합니다.
동일한 사이트에 README에는 update가 되지 않았었던 것이군요.
제가 더 열심히 찾아봤어야 했는데... 도움을 받게 되었습니다.
감사합니다.
혹시 보시는 분을 위해서...
alsong 님께서 올려주신 내용의 URL은 http://pauillac.inria.fr/~xleroy/linuxthreads/faq.html입니다.
동일 사이트의 README에는 안된다고 나오고, FAQ에는 예전 kernel에서는 안되고 2.2 이상부터는 된다고 하네요.
우리 모두 리얼리스트가 되자. 그러나 가슴에 이룰 수 없는 꿈을 가지자
kernel 2.4.20-8 ( redhat 9.0 )에서는 현재 ps
kernel 2.4.20-8 ( redhat 9.0 )에서는 현재 ps aux나 pstree를 했을 경우에 프로세서가 한개로 보입니다.
그리고 모든 thread에서 processor id를 얻어보면.. 똑같습니다.
thread쪽으로는 너무 많이 변하는 것 같네요..
댓글 달기