help icon indicating copy to clipboard operation
help copied to clipboard

Strange thread id within different threads

Open sergorl opened this issue 7 years ago • 5 comments

I try to make multithreaded tcp-server: on each accept incoming connection I make thread which reads from client and prints it on server side. I made my project based on example. So here is my idea in the code snippet below:

typedef struct {
    uv_stream_t* stream;
    uv_alloc_cb alloc_cb;
    uv_read_cb read_cb;
} info_t;

void work_thread(void* info_) {
    info_t* info = (info_t*) info_;
    uv_read_start(info->stream, info->alloc_cb, info->read_cb);
}

void on_new_connection(uv_stream_t *server, int status) {
    if (status < 0) {
        fprintf(stderr, "New connection error %s\n", uv_strerror(status));
        // error!
        return;
    }

    uv_tcp_t *client = (uv_tcp_t*) malloc(sizeof(uv_tcp_t));
    uv_tcp_init(loop, client);

    if (uv_accept(server, (uv_stream_t*) client) == 0) {

        info_t* info = (info_t*) malloc(sizeof(info_t));

        info->stream = (uv_stream_t*) client;
        info->alloc_cb = alloc_buffer;
        info->read_cb = echo_read;

        uv_thread_t thread_id;
        uv_thread_create(&thread_id, work_thread, info);
        uv_thread_join(&thread_id);
    }
    else {
        uv_close((uv_handle_t*) client, on_close);
    }
}

And inside echo_read() I call uv_thread_self() to get to know thread id:

void echo_read(uv_stream_t *client, ssize_t nread, const uv_buf_t *buf) {

    if (nread > 0) {
            ...

            printf("Send from thread %d\n", uv_thread_self());

            ...

            return;
        }
    }
    if (nread < 0) {
        if (nread != UV_EOF)
            fprintf(stderr, "Read error %s\n", uv_err_name(nread));
        uv_close((uv_handle_t*) client, on_close);
    }

    free(buf->base);
}

Then I connect with two different telnets (imitate client side) and print some data to client. But on the server side I see that thread ids in different client connectios are the same and always equals 0. Why does it happen? Where did I make a mistake?

I have:

  • uv_version_string() returns this 1.9.1;
  • os: windows 7 64-bit;
  • compiler: gcc (x86_64-posix-seh-rev0, Built by MinGW-W64 project) 7.3.0.

sergorl avatar Apr 09 '18 16:04 sergorl

https://github.com/libuv/libuv/issues/1791#issuecomment-379765025 - if anything is still unclear, can you ask directed questions?

bnoordhuis avatar Apr 09 '18 16:04 bnoordhuis

@bnoordhuis , I don't uderstand you about uv_thread_self()... I made this code and It seems uv_thread_self() works properly and returns diffierent thread id from different threads:

#include <stdio.h>
#include <unistd.h>
#include <uv.h>

void hare(void *arg) {
    int tracklen = *((int *) arg);
    while (tracklen) {
        tracklen--;
        sleep(1);
        fprintf(stderr, "Hare ran another step from thread %d\n", uv_thread_self());
    }
    fprintf(stderr, "Hare done running!\n");
}

void tortoise(void *arg) {
    int tracklen = *((int *) arg);
    while (tracklen) {
        tracklen--;
        fprintf(stderr, "Tortoise ran another step from thread %d\n", uv_thread_self());
        sleep(3);
    }
    fprintf(stderr, "Tortoise done running!\n");
}

int main() {
    int tracklen = 10;
    uv_thread_t hare_id;
    uv_thread_t tortoise_id;
    uv_thread_create(&hare_id, hare, &tracklen);
    uv_thread_create(&tortoise_id, tortoise, &tracklen);

    uv_thread_join(&hare_id);
    uv_thread_join(&tortoise_id);
    return 0;
}

What's the idiomatic difference between code above and my code about creation of thread for each new connection?

sergorl avatar Apr 09 '18 16:04 sergorl

I made this code and It seems uv_thread_self()works properly and returns diffierent thread id from different threads

That code is fine. uv_thread_self() is well-defined only for threads created by libuv but that's what your example does.

What's the idiomatic difference between code above and my code about creation of thread for each new connection?

That you're not allowed to call e.g. uv_read_start() from a different thread than the one that called uv_accept().

bnoordhuis avatar Apr 09 '18 17:04 bnoordhuis

So how can I create the thead per each incoming connection from client and process each connection in own thread?

sergorl avatar Apr 09 '18 17:04 sergorl

Why would you want to? The point of event-driven I/O is that you don't have to spawn a thread per connection.

bnoordhuis avatar Apr 10 '18 16:04 bnoordhuis