[완료] 수시로 바뀌는 파일 디스크립터를 정확하게 쓰레드로 넘기는 방법

whxoans의 이미지

메인 쓰레드에서 accept로 접속을 기다리다
accept 직후 thread를 생성하고 그 쓰레드의 인자값을 accecpt를 한 socket의 file discriptor로 넘기고 있습니다.

문제는 accept 직후에 file discriptor를 thread로 넘기는 방법으로

Quote:
pthread_create(,,,&fd)
이런식으로 넘기는데
thread가 fd를 받기전에 값이 바뀌는 경우가 생긴다는 겁니다.

이런 경우에는 어떻게 처리가 가능한지 질문 드립니다.

byung82의 이미지

queue를 활용해보시는건 어떤신가여

queue check thread를 만드셔서 queue에 push시 이벤트 발생해서 pop 후 쓰레드 생성

이렇게 해보시면 쉽게 해결될거라 생각듭니다.

그럼

jick의 이미지

fd라는 변수를 재활용하시나 보죠? 저러면 fd의 값이 아니라 fd의 *주소*를 넘기는 건데 쓰레드가 동작을 시작하기 전에 accept를 한번 더 불러 버리면 fd의 값이 바뀔 테니 당연히 쓰레드에서 제대로 된 값을 읽을 수가 없죠.

엄밀하게 말해서 C 표준을 준수한다고 하기는 힘들지만, 그냥 (void *) fd로 넘기고 받는 쪽에서 거꾸로 typecasting하시면 될 겁니다.

whxoans의 이미지

type이 문제가 되는 것이 아니라
차일드 쓰레드에서 참조하고 있는 메인 쓰레드에 있는 변수가 어느 시점에 값이 바뀔지 모르니
이것을 차이들 쓰레드에서 특정 작업이 끝날때까지 바뀌지 않게 하거나 하는 등의 방법을 몰라
질문 드린겁니다~

결국 타이밍의 문제를 말씀드린겁니다.

bushi의 이미지

주소를 넘기면서 아무런 조치도 취하지 않으니 그 주소에 담긴 값이 변하는 것이라는 설명이고요.

이것저것 처리하려면 비용이 비싸질 수 있으니 주소대신 값을 직접 넘기는 꼼수가 어떻겠냐고 조언해주신겁니다.

국어가 너무 어려워서 글로 쓰면 잘 전달이 안되니 코드로 보여주시기 까지 했는데,
글은 보지도 않고 코드만 보곤 웬 동문서답이냐라고 댓글다시면 곤란하죠.

OTL

whxoans의 이미지

말씀하신대로 저야 말로 동문서답을 한 격이 되었네요;;
위처럼 처리해서 정상 처리 되는 것을 확인하였습니다.

이놈의 덤벙댐은;;;;

bushi의 이미지

jick 님의 댓글에 동감합니다. 좀 간질간질하죠 ^^

언젠가 두드렸던 코드 조각

struct completion {
        int done;
        pthread_mutex_t wait;
        pthread_cond_t cond;
};
 
static void init_completion(struct completion *completion)
{
        completion->done = 0;
        pthread_mutex_init(&completion->wait, NULL);
        pthread_cond_init(&completion->cond, NULL);
}
 
static void destroy_completion(struct completion *completion)
{
        pthread_mutex_destroy(&completion->wait);
        pthread_cond_destroy(&completion->cond);
}
 
static void wait_for_completion(struct completion *completion)
{
        pthread_mutex_lock(&completion->wait);
        if (!completion->done) {
                pthread_cond_wait(&completion->cond, &completion->wait);
        }
        completion->done = 0; 
        pthread_mutex_unlock(&completion->wait);
}
 
static void complete(struct completion *completion)
{
        pthread_mutex_lock(&completion->wait);
        completion->done = 1;
        pthread_cond_signal(&completion->cond);
        pthread_mutex_unlock(&completion->wait);
}

대강 이렇게

#include <stdio.h>
#include <unistd.h>
#include <pthread.h>
 
#include "completion.h"
 
struct my_thread_info {
        int count;
        pthread_mutex_t count_mutex;
        struct completion arg_catch;
};
 
static void thread_cleanup(void *arg)
{
        struct my_thread_info *ti = arg;
        int i;
 
        pthread_mutex_lock(&ti->count_mutex);
        i = ti->count;
        ti->count--;
        pthread_mutex_unlock(&ti->count_mutex);
 
        printf("terminating %d\n", i);
        fflush(stdout);
}
 
static void *thread_proc(void *arg)
{
        struct my_thread_info *ti = arg;
        int i;
 
        pthread_mutex_lock(&ti->count_mutex);
        i = ti->count;
        pthread_mutex_unlock(&ti->count_mutex);
 
        complete(&ti->arg_catch);
 
        pthread_cleanup_push(thread_cleanup, ti);
 
        printf("processing %d\n", i);
        fflush(stdout);
 
        sleep(2);
 
        pthread_cleanup_pop(1);
 
        return (void*)NULL;
}
 
int main()
{
        struct my_thread_info ti;
        pthread_t tmp_tid;
        int ret;
        int i;
 
        ti.count = 0;
        pthread_mutex_init(&ti.count_mutex, NULL);
 
        init_completion(&ti.arg_catch);
 
        for (i = 1; i < 10; i++) {
                pthread_mutex_lock(&ti.count_mutex);
                ti.count = i;
                pthread_mutex_unlock(&ti.count_mutex);
 
                ret = pthread_create(&tmp_tid, NULL, thread_proc, &ti);
                if (ret < 0) {
                        perror("pthread_create()");
                        break;
                }
 
                wait_for_completion(&ti.arg_catch);
 
                pthread_detach(tmp_tid);
        }
 
        do {
                sleep(1);
                pthread_mutex_lock(&ti.count_mutex);
                i = ti.count;
                pthread_mutex_unlock(&ti.count_mutex);
        } while (i != 0);
 
        destroy_completion(&ti.arg_catch);
 
        pthread_mutex_destroy(&ti.count_mutex);
 
        return 0;
}                                                  

OTL

kaeri17의 이미지

사실 void*가 int형보다 크다는 보장이 C에서는 없기 때문에 malloc한 다음 그 메모리에 fd를 저장해서 쓰레드에 보내는 것이 원칙입니다. (void*)fd를 하면 값에 의한 복사가 되어서 잘 넘어가죠.

위에분이 잘 설명해 주셨는데 동문서답이라 하시니 그러네요 좀..

댓글 달기

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