pthread_mutex_lock 중복 호출 관련 질문

ansdusah의 이미지

안녕하세요.
아래 code에서 main 함수에서 먼저 pthread_mutex_lock을 실행하고, 쓰레드 내부에서 한번더 pthread_mutex_lock을 실행하면 dead-lock 현상이 발생한다고 예상되는 데, 실제 실행하면, 제 예상과는 다르게 문제없이 동작합니다.
아래 code에서 Ver.1로 돌릴 때와 Ver.2로 돌릴 때의 차이점을 알고 싶습니다.
기존 글을 검색해보았으나 이해가 어려워 다시 글을 올립니다.

#include <pthread.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <vector>
#include <iostream>
 
using namespace std;
 
void *ping(void *);
void *pong(void *);
 
pthread_mutex_t sync_mutex;
pthread_cond_t  sync_cond;
 
pthread_mutex_t gmutex = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t  gcond  = PTHREAD_COND_INITIALIZER;
 
int main()
{
    vector<void *(*)(void *)> thread_list;
    vector<pthread_t> tident(10); 
    int thresult;
    int status;
    int i;
 
    pthread_mutex_init(&sync_mutex, NULL);
    pthread_cond_init(&sync_cond, NULL);
 
    thread_list.push_back(pong);
    thread_list.push_back(ping);
 
    for(i = 0; i < thread_list.size(); i++ )
    {
        pthread_mutex_lock(&sync_mutex);              // Ver.1
        //pthread_mutex_lock(&sync_mutex);            // Ver.2
        if (pthread_create(&tident[i], NULL, thread_list[i], (void *)NULL) <0)
        {
            perror("error:");
            exit(0);
        }
        pthread_cond_wait(&sync_cond, &sync_mutex);
        pthread_mutex_unlock(&sync_mutex);            // Ver.1
        //pthread_mutex_unlock(&sync_mutex);          // Ver.2
    }
    for (i = 0; i < tident.size(); i++)
    {
        pthread_join(tident[i], (void **)&status);
    }
}
 
void *ping(void *data)
{
    int i=0;
    pthread_mutex_lock(&sync_mutex);
    pthread_cond_signal(&sync_cond);
    pthread_mutex_unlock(&sync_mutex);
    while(1)
    {
        pthread_mutex_lock(&gmutex);
        printf("%d : ping\n", i);
        pthread_cond_signal(&gcond);
        pthread_cond_wait(&gcond, &gmutex);
        pthread_mutex_unlock(&gmutex);
        usleep(random()%100);
        i++;
    }
}
 
void *pong(void *data)
{
    int i = 0;
    pthread_mutex_lock(&sync_mutex);
    sleep(1);
    pthread_cond_signal(&sync_cond);
    pthread_mutex_unlock(&sync_mutex);
    while(1)
    {
        pthread_mutex_lock(&gmutex);
        pthread_cond_wait(&gcond, &gmutex);
        printf("%d : pong\n", i);
        pthread_cond_signal(&gcond);
        pthread_mutex_unlock(&gmutex);
        i++;
    }
}
jick의 이미지

Deadlock이 걸리려면 서로가 서로를 기다리는 상황이 되어야죠. 이를테면 쓰레드 A가 락 L1을 걸고 L2를 기다리고 있는데, 쓰데르 B는 락 L2를 걸고 L1을 기다리고 있는 게 가장 전형적인 상황이죠.

근데 올려주신 코드에선 락이 딱 두 가지밖에 없고, 어떤 상황에서도 "락 하나를 이미 건 상태에서 두번째 락을 기다리는" 코드가 보이지 않는데요.

ansdusah의 이미지

ping()과 pong()에서 호출하는 뮤텍스락을 말씀하시는거지요?
맞습니다. 저도 그렇게 생각하고 있습니다. 그런데, main문에서 호출하는 pthread_mutex_lock은 어떻게 이해해야하는지 모르겠습니다.
main문에서 락을 걸어주고 ping이나 pong 함수(thread)에서 또다시 락을 걸게되는 상황이 오는걸텐데, 그럼 데드락이 발생하는것 아닌가? 라는 의문에서 시작된 질문입니다.
main문에서 호출하는 pthread_mutex_lock이 있고 없고에 따라 어떤 차이가 발생하는지가 궁금합니다.

jick의 이미지

https://linux.die.net/man/3/pthread_cond_wait

> These functions atomically release mutex and cause the calling thread to block on the condition variable cond ...

즉, pthread_cond_wait로 기다리고 있는 쓰레드는 기다리는 동안 mutex를 잡고 있지 않습니다.

* 그리고 웬만하면 코드 질문을 할 때에는 (1) 질문에 관련된 부분만 남기고 다 지우고 (2) 원래 질문하고 싶었던 것과 같은 동작을 하는지 확인한 다음 올려주세요. 질문하는 사람은 부탁하는 입장인데 "자 여기 50줄짜리 코드가 있는데 이중에 제가 어느 부분이 궁금한지는 알아서 찾아서 답변해 주세요" 하는 건, 별로 원하는 답변을 못 얻을 가능성이 높습니다.

ansdusah의 이미지

(1) 질문에 관련된 부분만 남기고 다 지우고
: 이 부분에 대해서는 제가 생각이 짧았네요, 앞으로는 축약하도록 하겠습니다. bold 처리로 포인트를 주고싶었는데 그 방법을 몰라 주석으로 처리했습니다.

(2) 원래 질문하고 싶었던 것과 같은 동작을 하는지 확인한 다음 올려주세요. 질문하는 사람은 부탁하는 입장인데 "자 여기 50줄짜리 코드가 있는데 이중에 제가 어느 부분이 궁금한지는 알아서 찾아서 답변해 주세요" 하는 건, 별로 원하는 답변을 못 얻을 가능성이 높습니다.
: 제가 올린 본문을 보시면,
'~ 실제 실행하면, 제 예상과는 다르게 문제없이 동작합니다.'
실제 실행해보고 올린 질문글 입니다.^^

답변 감사합니다.

jick의 이미지

제가 좀 오해의 소지가 있게 적은 것 같은데, 부연설명을 하자면

(1) 질문에 관련된 부분만 남기고 다 지우고
(2) 다 지워진 *그 상태의 프로그램*을 컴파일해서 돌려봐서 원래 질문하고 싶은 상황과 동일하게 동작하는 것을 확인한 후

질문을 하는 것이 좋습니다.

최악의 경우는 반대로 하는 겁니다.

(1) 일단 질문을 하고 싶은 동작을 하는 것을 확인한 후,
(2) 질문과 "관련없는" 부분을 지우고,

"이 코드가 이러이러하게 동작하는데 왜 그럴까요? 아 중간에 (생략)한 부분은 제가 안 중요한 것 같아서 가위질했습니다."

...뭐 그러면 보통 "최소한 컴파일이 되는 코드를 올려주세요!!!11!" 하는 답글이 달리죠. -.-

furmuwon의 이미지

pthread_cond_wait 내부를 보시면
매개변수로 들어오는 lock 을
unlock
wait
lock
하거든요...

http://androidxref.com/9.0.0_r3/xref/bionic/libc/bionic/pthread_cond.cpp#__pthread_cond_timedwait
(간편하게 glibc 말고 bionic 로 링크합니다.)

이렇게 보셔서 lock, unlcok 체크해 보시면 될 것 같습니다.

댓글 달기

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