pthread로 쓰레드를 생성하는 경우에...

swunk의 이미지

pthread로 쓰레드를 생성한 경우에 아래와 같은 코드 절차를 따라 쓰레드를 생성한다고 어디선가(?) 보았습니다. (시간이 조금 지나긴 했습니다만...)

pthread_create(..., foo, ...) -> __clone(foo, ., clone_flags, ....){
........
x=clone(clone_flags, .....);
if (x==0){
foo(.....);
}
...........
}
-> clone(clone_flags,....) -> sys_clone() -> do_fork(clone_flags, .....)

그렇다면 결국에는 커널영역에는 task_struct 형태로 PCB가 존재해야 되는데...PS로 확인을 해보면 없네요...

반대로 clone()으로 쓰레드를 생성한 경우에는 PS로 확인을 해 보면 존재하구요...

저번에도 질문을 올렸는데 명확한 답변을 못드려서 다시 드립니다.

powerc20의 이미지

리눅스 커널 2.6을 사용하시는 것 같습니다.
ps는 pid가 아니라 tgid를 보고 프로세스를 출력해 주는데
2.6부터는 pthread_create로 생성을 하면 tgid가 같게 생성을 합니다.
2.4까지는 tgid가 다르게 생성 되어서 ps를 해보면 여러러개의 프로세스가 보입니다.

ps) 초보의 답변입니다. 틀린점 있으면 고수님들 지도 바랍니다.
즐거운 하루 되세요.

ps) pgid가 아니라 tgid입니다. 수정했습니다.

ps) 저도 위 내용을 더 알아볼려고 커널 2.4 코드를 분석했는데 이상하게 코드에서는 같은 프로세스 안의 쓰레드는

같은 tgid를 사용할 것 같은데 실제 결과는 아니더군요. 제가 뭔가를 잘 못 알고 있는것 같습니다. 고수님들 지도 바랍니다.

swunk의 이미지

여기 저기 뒤져보니 유사한 답을 찾을 수 있었습니다.

일단 제가 검색해 본 결과로는 2.4 커널 에서는 clone()시스템 콜을 기반으로 수행되는 커널에서는 쓰레드와 프로세스의 차이가 스케쥴러 관점에서는 차이가 없다고 하는군요...
그런데 제가 위에서 테스트 해본 상황에서 그렇게 나온 이유는 저는 redhat 9.0 (2.4.20-8) 에서 확인을 했는데 redhat9.0 에서 NPTL feature를 패치를 해서 하나의 PID로 보였던 겁니다. 관련 내용은 아래 링크 참조하시구요...

http://www.redhat.com/docs/manuals/linux/RHL-9-Manual/release-notes/x86/

그런데...
제가 2.6 커널을 모두 분석한 것은 아니지만...understanding linux kernel 3ed 에 나와 있는...그 중에서는 process에 관한 내용은 전부 훓어 보았는데 NPTL에 대한 언급은 없던걸로 기억하고 쓰레드 스케쥴링에 있어서 많은 변화가 있다고는 보지 못햇습니다.

2.6대로 넘어오면서는 위에서 질문한 내용..즉 쓰레드는 프로세스와 달리 task_struct에 의해서 관리되지 않는다가 맞나요? NPTL이라는 feature 때문에...

NPTL을 스터디 해 봐야 갔군요...

wish의 이미지

커널 버전 2.6 을 기준으로 이야기해 보겠습니다.

pthread_create() 로 쓰레드를 생성한 뒤, ps -L 명령으로 한 번 확인해 보세요. -L 은 쓰레드도 표시하라는 옵션이므로 생성된 쓰레드를 확인할 수 있을 것입니다. 반면 clone() 으로 생성한 쓰레드는 그냥 ps 명령으로도 보일 것입니다. 그러나 clone() 을 호출할 때 FLAGS 인자에 CLONE_THREAD 를 첨가해 보시고 다시 실행하시면, 그냥 ps 명령으로는 생성한 쓰레드를 보실 수 없을 것 입니다. ps -L 명령을 통해서만 확인 가능합니다.

일단 위의 실험을 통해서, pthread_create()로 만든 쓰레드와 마찬가지로, clone() 으로 만든 쓰레드/프로세스도 인자를 어떻게 주느냐에 따라서 ps 명령으로 보이지 않을 수 있다는 것을 알 수 있습니다. ps 는 기본적으로 프로세스만 보여주기 때문에, 쓰레드는 -L 인자를 붙이지 않으면 보여주지 않습니다. 따라서 clone() 씨스템 콜은 프로세스 혹은 쓰레드 모두를 만들 수 있다는 이야기도 되겠습니다.

이제 질문에 대한 답을 한번 만들어보죠.

"2.6대로 넘어오면서는 위에서 질문한 내용..즉 쓰레드는 프로세스와 달리 task_struct에 의해서 관리되지 않는다가 맞나요?"

위 질문에 대한 대답은 아니오라고 생각합니다. 커널 2.6에서도 리눅스 스케줄러 입장에서는 모든 쓰레드와 프로세스는 공히 task_struct 로 표현됩니다. 따라서 NPTL 구현체에 따라 만들어진 함수라고 해서 특별히 따로 표현되거나 하지는 않습니다. 2.6 커널에서도 역시 스케줄러 입장에서는 쓰레드와 프로세스는 아무런 차이를 가지지 않죠. 위 실험에서 pthread_create()나 clone(..., | CLONE_THREAD | ...)으로 만들어서 ps 명령어로 보이지 않는(그러나 ps -L로는 보이는) 프로세스와 clone() 으로 만들어서 ps 명령어를 통해 보이는 프로세스(혹은 쓰레드)는 모두 스케줄러 입장에서는 같은 것으로 취급합니다.

사실 프로세스는 시스템 자원 할당의 단위이고 쓰레드는 스케줄의 단위라고 보는 것이 가장 간단합니다. 쓰레드 개념이 없던 오래 전 유닉스는 프로세스가 자원 할당의 단위와 스케줄링의 단위를 겸했었습니다. 그러나 현대에 와서 그 두가지가 분리되면서 하나의 프로세스에 여러개의 쓰레드가 생길 수 있게 된 것입니다. 전통적인 유닉스 프로세스는 쓰레드를 한 개만 가지고 있다고 생각할 수도 있습니다.

리눅스는 clone() 시스템 콜을 어떻게 호출 하느냐에 따라서 시스템 자원을 서로 공유할 수 있기 때문에, 사실 fork() 로 만들어진 프로세스도 clone() 시스템 콜을 적당하게 호출해서 여러 자원을 공유하지 않게 만든 것에 불과합니다. 이런 맥락에서 리눅스에서는 프로세스와 쓰레드의 차이가 없다라는 말이 나온 것 같습니다.

쓰레드와 프로세스라는 말에 너무 현혹되지 마시고, 리눅스는 커널 스케줄링 단위를 유저 공간에서 만들 때 clone() 시스템 콜을 사용하고, 어떻게 호출하느냐에 따라서 성질이 다른 스케줄링 단위를 만들 수 있다. 그리고 그 성질에 따라서 전통적인 유닉스 프로세스로 만들 수도 있고, vfork() 로 만들어진 프로세스처럼 만들 수도 있고, POSIX 표준 준수의 pthread 로도 만들 수 있고, 표준과는 다른 리눅스 특유의 쓰레드로도 만들 수 있다는 정도가 맞는 표현이라고 생각합니다.

첨언하자면 2.4 시절의 pthread 구현은 LinuxThreads 이었고 이는 쓰레드 생성시마다 PID 가 달라졌는데, 이는 POSIX thread 표준과 다른 방식이었습니다. 잘은 모르지만 이런 식으로 구현할 수 밖에 없었던 것은, 2.4 커널 내부 구조 특히 clone() 시스템 콜 구현의 한계가 아니었나 추측합니다(그런 문서를 읽은 기억이 희미하게나마 있습니다). 이것을 NPTL 로 구현하면서, clone() 시스템 콜과 그 밖의 다른 커널 내부 구조를 효휼적인 pthread 구현을 위해서 많은 부분 수정하고, 유저 레벨 라이브러리도 그에 맞게 새롭게 구현한 듯 싶습니다. NTPL 디자인 문서에서 그런식의 이야기를 한 것을 본 듯 합니다.

사실 장황하게 썼지만 저도 최근에서야 좀 뚜렷하게 알게 된 것이라 잘못된 부분이 있을 수도 있습니다 :) 그러나 제일 위의 pthread 와 clone 의 차이는 실험해 봤으므로 거의 확실하구요 ^^ 커널 고수 분 계시면 가감없이 태클 부탁 드리겠습니다~

swunk의 이미지

java에서 쓰레드 생성은 어떤가요 ?
2.4.20 커널에서 확인을 해 보았습니다. 자바 어플리케이션에서 4개의 쓰레드를 생성하고 ps -ef로 확인을 해보니 아래와 같이 13개의 쓰레드가 확인이 됩니다.
어떻게 이해를 해야 하나요 ? jdk에서도 실제 해당 시스템콜(clone)을 호출해서 구현이 되어 있을것 같은데...

root 1610 1608 0 15:22 pts/0 00:00:00 -bash
root 1653 1610 0 15:22 pts/0 00:00:00 screen
root 1654 1653 0 15:22 ? 00:00:00 SCREEN
root 1655 1654 0 15:22 pts/1 00:00:00 /bin/bash
root 1676 1654 0 15:22 pts/2 00:00:00 /bin/bash
root 1697 1654 0 15:22 pts/3 00:00:00 /bin/bash
root 1759 1655 6 15:24 pts/1 00:00:00 java ThreadTester
root 1760 1759 0 15:24 pts/1 00:00:00 java ThreadTester
root 1761 1760 0 15:24 pts/1 00:00:00 java ThreadTester
root 1762 1760 0 15:24 pts/1 00:00:00 java ThreadTester
root 1763 1760 0 15:24 pts/1 00:00:00 java ThreadTester
root 1764 1760 0 15:24 pts/1 00:00:00 java ThreadTester
root 1765 1760 0 15:24 pts/1 00:00:00 java ThreadTester
root 1766 1760 0 15:24 pts/1 00:00:00 java ThreadTester
root 1767 1760 0 15:24 pts/1 00:00:00 java ThreadTester
root 1768 1760 0 15:24 pts/1 00:00:00 java ThreadTester
root 1769 1760 0 15:24 pts/1 00:00:00 java ThreadTester
root 1770 1760 0 15:24 pts/1 00:00:00 java ThreadTester
root 1771 1760 0 15:24 pts/1 00:00:00 java ThreadTester
root 1772 1676 0 15:24 pts/2 00:00:00 ps -ef

그리고...
"커널 2.6에서도 리눅스 스케줄러 입장에서는 모든 쓰레드와 프로세스는 공히 task_struct 로 표현됩니다." 라는 말씀은 결국 스케쥴러는 해당 task_struct가 담고 있는 object가 프로세스인지 쓰레드인지 확인할 수 없다(확인하지 않는다). 라고 이해가 됩니다. 물론 메모리 영역을 공유하기 때문에 두개의 차이는 해당 task_struct의 mm_struct를 따라가 보면 차이가 있겠지요 ? (mm_struct를 따라가 보면 어떤 차이가 있는지 여쭤봐도 될까요 ?)

그렇기 때문에 스케쥴링의 관점에서 보면 (리눅스에서는) 차이가 없다 라고 말 할 수 있는거지요 ?

뭐 이거 줄줄이 질문하기 뭐합니다만 하나 더 여쭙겠습니다.

ps 소스를 제가 확인하지 않았지만 ps -L 옵션을 주게 되면 쓰레드 정보까지 출력하는 걸로 봐서는 task_struct의 어떤 field 중 해당 object가 쓰레드 인지 프로세스인지를 구분하는 놈이 있다고 생각되어 집니다. (list_head에서 고구마 줄기 캐듯이 찾아가면서 출력하는게 ps 프로그램일 테니까요...)
그 놈이 누군가요 ? 위에분 말씀과 같이 tgid 값을 보고 그게 같으면 하나만 출력을 하고 그렇지 않으면 모두 출력을 하게 되나요 ? (2.6에서는 쓰레드들의 tgid가 같고, 2.4에서는 그 값이 다르기 때문에 차이가 나는것으로 이해가 되긴 하는데...명확하지가 않네요...)

그럼 여러 고수님들의 답변 부탁드립니다.

점점 NPTL이라는 놈이 어떻게 구현되어 있을지 궁금해 지는 군요...

댓글 달기

Filtered HTML

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

BBCode

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param>
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

Textile

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • You can use Textile markup to format text.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Markdown

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • Quick Tips:
    • Two or more spaces at a line's end = Line break
    • Double returns = Paragraph
    • *Single asterisks* or _single underscores_ = Emphasis
    • **Double** or __double__ = Strong
    • This is [a link](http://the.link.example.com "The optional title text")
    For complete details on the Markdown syntax, see the Markdown documentation and Markdown Extra documentation for tables, footnotes, and more.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Plain text

  • HTML 태그를 사용할 수 없습니다.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 줄과 단락은 자동으로 분리됩니다.
댓글 첨부 파일
이 댓글에 이미지나 파일을 업로드 합니다.
파일 크기는 8 MB보다 작아야 합니다.
허용할 파일 형식: txt pdf doc xls gif jpg jpeg mp3 png rar zip.
CAPTCHA
이것은 자동으로 스팸을 올리는 것을 막기 위해서 제공됩니다.