thread 에서.. lock 문제

thisnome의 이미지

전역변수가 있습니다.

int global = 1;

전역변수값을 1과 2로 반복해서 바꾸는 쓰레드가 있습니다. (하나)

thread_chg()
{
    while(1)
    {
        if(global == 1)
            global = 2;
        else
            global = 1;
    }
}

전역변수값을 얻어서 사용하는 쓰레드가 여러개 있습니다.

thread_use()
{
    while(1)
    {
        use_global(global);
    }
}

제생각엔 thread_chg가 global에 1 이나 2를 write 하는 중에 global 을 read 한는 상태가 발생한다면, 1이나 2가 아닌 엉뚱한 값을 읽을 수도 있다고 생각하는데.. (그래서 lock이 필요할 것이라고)

테스트를 해보면 이상이 없습니다. write 하는 놈이 한놈이면 상관이 없는건가요? 궁금해서 질문 올립니다.

cronex의 이미지

음.... 조금 잘못 이해하고 계신듯하군요.
쓰레드 사용에 락이 필요한 이유는 두 쓰레드가 동시에 값에 접근하는 경우를 막기 위해서입니다. thishome님이 말씀하신거와 같은 쓰는 도중에 읽는.... 경우는 없다고 보시면 됩니다. 왜냐하면 그런 읽기 쓰기는 소프트웨어적인 부분이 아니라 하드웨어적으로 처리되는 부분이기 때문에 프로그래머가 신경 쓸 부분은 아니죠. (클럭이라는게 왜 존재하는 지에 대해 다시 한번 숙고해보시기 바랍니다.)
설명드리자면 예로 드신 코드에 더해서

thread_check()
{
    int buf = 0;

    while(1) {
        if ( buf <= global ) {
            buf += global;
        }
        else {
            buf = 0;
       }
   }
}

와 같은 쓰레드가 동시에 존재한다고 할때.....
if (buf <= global) 다음에 즉, buf+= global 가 실행되기 바로 직전에 thread가 스케줄링 되어서 thread_chg()로 넘어갔다면(혹은 SMP에서 다수의 cpu에서 도는 경우라면 동시에 서로 다른 cpu에서 실행되고 있었다면) thread_chg()의 코드가 실행된 이후에는 global의 값은 이전의 값과는 다른 값으로 바뀌었지만 thread_print() 함수에서는 이미 if문을 통해 global의 이전 값의 상태가 남아있습니다.
즉 global이란 값이 어떠한 상태를 의미하는 값이라고 할 때, 상태에 대한 값이 변했는데도 프로그램의 어떠한 부분에서는 이러한 바뀐 상태가 적용되지 않을 수도 있다는데 문제가 있다는 겁니다. 조건이나 상황이 바뀌었는데도 이전 처리를 그대로 하게될 수가 있어서 예상외의 값이 나올 수도 있습니다.
이러한 부분이 동기화 문제라고 하는데.... 이에 대한 자세한 내용은 어떤 운영체제 책에라도 자세히 나와있으니 참고하시기 바랍니다.[/code]

------------------------------------------------------------
이 멍청이~! 나한테 이길 수 있다고 생각했었냐~?
광란의 귀공자 데코스 와이즈멜 님이라구~!

happyjun의 이미지

cronex wrote:
쓰레드 사용에 락이 필요한 이유는 두 쓰레드가 동시에 값에 접근하는 경우를 막기 위해서입니다. thishome님이 말씀하신거와 같은 쓰는 도중에 읽는.... 경우는 없다고 보시면 됩니다.

없다고는 볼 수 없습니다.

global = 1 이 모든 CPU, OS, Compiler에서 원자성atomic 을 보장해 주지 않습니다. 또한 원자성외에도 global = 1 을 한 정확한 시점이 보장되어야 한다면 lock을 걸어야 합니다.

클럭.. 보다는 SMP, cache 등을 생각해보는 것이 좋을 것 같습니다.

----------------------------------------
http://moim.at
http://mkhq.co.kr

thisnome의 이미지

cronex wrote:
음.... 조금 잘못 이해하고 계신듯하군요.
쓰레드 사용에 락이 필요한 이유는 두 쓰레드가 동시에 값에 접근하는 경우를 막기 위해서입니다. thishome님이 말씀하신거와 같은 쓰는 도중에 읽는.... 경우는 없다고 보시면 됩니다. 왜냐하면 그런 읽기 쓰기는 소프트웨어적인 부분이 아니라 하드웨어적으로 처리되는 부분이기 때문에 프로그래머가 신경 쓸 부분은 아니죠.(클럭이라는게 왜 존재하는 지에 대해 다시 한번 숙고해보시기 바랍니다.)

쓰레드 사용에 락이 필요한 이유가 동시에 값에 접근하는 경우를 막기 위해서라고 하셨는데.. 쓰는 도중에 읽는 경우도 동시에 값에 접근하는 경우라서 질문 드린 것입니다.
클럭 부분 말씀도 한 클럭동안 하나의 데이타에 쓰는 동작을 모두 할 수는 없지 않겠습니까? cronex 님의 글을 읽어보면 어떤 데이터형에 값을 쓰는것은 자동으로 원자성이 보장된다는 말씀 같이 느껴집니다.

thisnome의 이미지

happyjun wrote:
cronex wrote:
쓰레드 사용에 락이 필요한 이유는 두 쓰레드가 동시에 값에 접근하는 경우를 막기 위해서입니다. thishome님이 말씀하신거와 같은 쓰는 도중에 읽는.... 경우는 없다고 보시면 됩니다.

없다고는 볼 수 없습니다.

global = 1 이 모든 CPU, OS, Compiler에서 원자성atomic 을 보장해 주지 않습니다. 또한 원자성외에도 global = 1 을 한 정확한 시점이 보장되어야 한다면 lock을 걸어야 합니다.

클럭.. 보다는 SMP, cache 등을 생각해보는 것이 좋을 것 같습니다.

그럼 제가 올린 첫번째 질문의 코드는 운이 좋아 에러가 없었을뿐 위험을 내재한 프로그램이 맞다는 말씀이시죠?
제 주위에서 이 문제가지고 이상이 없다는 분이 있어서.. 테스트를 해보려구 돌렸는데... 몇시간을 돌려도 이상이 없기에 질문 드린겁니다. :D

추가 답변 부탁드립니다~

pool007의 이미지

thisnome wrote:
happyjun wrote:
cronex wrote:
쓰레드 사용에 락이 필요한 이유는 두 쓰레드가 동시에 값에 접근하는 경우를 막기 위해서입니다. thishome님이 말씀하신거와 같은 쓰는 도중에 읽는.... 경우는 없다고 보시면 됩니다.

없다고는 볼 수 없습니다.

global = 1 이 모든 CPU, OS, Compiler에서 원자성atomic 을 보장해 주지 않습니다. 또한 원자성외에도 global = 1 을 한 정확한 시점이 보장되어야 한다면 lock을 걸어야 합니다.

클럭.. 보다는 SMP, cache 등을 생각해보는 것이 좋을 것 같습니다.

그럼 제가 올린 첫번째 질문의 코드는 운이 좋아 에러가 없었을뿐 위험을 내재한 프로그램이 맞다는 말씀이시죠?
제 주위에서 이 문제가지고 이상이 없다는 분이 있어서.. 테스트를 해보려구 돌렸는데... 몇시간을 돌려도 이상이 없기에 질문 드린겁니다. :D

추가 답변 부탁드립니다~

네. 운이 좋아서 되는 것 맞습니다.

쓰레드 프로그래밍의 가장 어려운점이, 에러를 찾기 어렵다는 것 (현재의 경우처럼 에러가 뜨질 않죠)과 한번 발생했던 에러를 다시 시뮬레이션 하는 게 불가능하다는 점입니다.

지금 하신 테스트는 이 컴파일러에서 이 CPU에서 여러시간동안 성공적으로 수행되었다는 것 외에는 아무것도 보장해주는 것이 없는 셈입니다..

--
Passion is like genius; a miracle.

cronex의 이미지

아... -_-;; 그렇군요;;
대입식이란 것도 cpu에서의 instruction으론 여러개로 쪼개어지지요 -_-;;
이렇게 자꾸 자극을 받아야 생각이 난답니다;;
지금 읽어보니 원래 쓰려고 했던 내용도 아니었군요;;
쓰고 고치고 그러다 보니 내용이 바뀐듯 -_-;;
아무튼 thisnome님께 잘못된 지식을 알려드리지 않게되서 다행이군요.

------------------------------------------------------------
이 멍청이~! 나한테 이길 수 있다고 생각했었냐~?
광란의 귀공자 데코스 와이즈멜 님이라구~!

댓글 달기

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
이것은 자동으로 스팸을 올리는 것을 막기 위해서 제공됩니다.