c - 似乎 pthread_create 正在覆盖以前的线程

标签 c linux multithreading pthreads

我正在尝试编写一个 IRC 类型的聊天客户端,它具有可以连接到服务器的客户端。我试图让它在本地 atm 上工作(使用 FIFOS 而不是套接字)。

我遇到了以下我似乎无法解决的问题:

接受新的客户端连接后,我想为该客户端(在服务器上)创建一个新线程来处理来自该客户端的输入。

为此,我有以下代码(完整代码在底部):

while(1) {
  .
  .
  .
  if (pthread_create(&thread, NULL, client_handler, &new_client) != 0)
    printf("Couldn't create a thread to listen to the client.... Not ok \n");
}

这适用于 1 个连接的客户端。

当我尝试连接另一个客户端时,似乎执行方法 client_handler 的前一个线程停止运行。 我知道这是因为服务器停止接受来自该客户端的输入,但新线程工作正常(处理新连接的客户端的线程)。

我想知道我的方法是否有误,或者我是否没有正确使用 pthread_create。 有人有什么建议吗?

void server_listen() {
    Client new_client;
    ClientNode temp;
    buffint client_name_length;
    char client_name[CLIENT_NAME_SIZE];
    char fifo_in[FIFO_NAME_SIZE], fifo_out[FIFO_NAME_SIZE];
    buffint client_pid;
    char ack[4] = "/ack";
    char inuse[6] = "/inuse";
    pthread_t thread;
    buffint length;
    ClientNode it;
    buffint message_length;
    char message[MESSAGE_LENGTH];
    pthread_mutexattr_t attr; 

    while (1) {
        memset(client_name, 0, CLIENT_NAME_SIZE);
        client_name_length.data =0;
        if (read_helper(irc_server.server_fifo, client_name_length.buff,
                sizeof(int)) == -1)
            return; /* error */
        if (read_helper(irc_server.server_fifo, client_pid.buff, sizeof(int))
                == -1)
            return; /* error */
        if (read_helper(irc_server.server_fifo, client_name, client_name_length.data) == -1)
            return; /* error */

        pthread_mutexattr_init(&attr);
        pthread_mutexattr_settype(&attr,PTHREAD_MUTEX_ERRORCHECK_NP);
        pthread_mutex_init(&new_client.fifo_in_lock, &attr);

        printf("Reading from a new client, with name: %s\n", client_name);
        new_client.pid = client_pid.data;
        strncpy(new_client.name, client_name, client_name_length.data);
        new_client.name_length = client_name_length.data;
        sprintf(fifo_in, "fifo-%d-in", client_pid.data);
        sprintf(fifo_out, "fifo-%d-out", client_pid.data);
        new_client.fifo_in = open(fifo_in, O_WRONLY);
        if (new_client.fifo_in == -1)
            return; /* error */
        new_client.fifo_out = open(fifo_out, O_RDONLY);
        if (new_client.fifo_out == -1)
            return; /* error */

        read_lock();
        temp = client_exists_by_name(&irc_server.clients, client_name, client_name_length.data);
        read_unlock();

        if (temp != NULL) {
            pthread_mutex_lock(&new_client.fifo_in_lock);
            length.data = 6;
            if (write_helper(new_client.fifo_in, length.buff, sizeof(int))
                    == -1) {
                //TODO: What do we do if writing to the fifo_out failed?
                printf( "Writing to the fifo-out failed for some unknown reason \n");
                return;
            }
            if (write_helper(new_client.fifo_in, inuse, length.data) == -1) {
                //TODO: What do we do if writing to the fifo_out failed?
                printf( "Writing to the fifo-out failed for some unknown reason \n");
                return;
            }
            pthread_mutex_unlock(&new_client.fifo_in_lock);
            continue;
        }


        write_lock();
        insert_node(&irc_server.clients, new_client);
        write_unlock();

        length.data = 4;

        pthread_mutex_lock(&new_client.fifo_in_lock);
        if (write_helper(new_client.fifo_in, length.buff, sizeof(int)) == -1) {
            //TODO: What do we do if writing to the fifo_out failed?
            printf("Writing to the fifo-out failed for some unknown reason \n");
            return;
        }
        if (write_helper(new_client.fifo_in, ack, length.data) == -1) {
            //TODO: What do we do if writing to the fifo_out failed?
            printf("Writing to the fifo-out failed for some unknown reason \n");
            return;
        }
        pthread_mutex_unlock(&new_client.fifo_in_lock);


        foreach(it, irc_server.clients){
            pthread_mutex_lock(&it->client.fifo_in_lock);   

            strncpy(message, new_client.name, new_client.name_length);
            strncat(message, " joined the chat", sizeof(" joined the chat"));
            message_length.data = sizeof(" joined the chat") + new_client.name_length;
            if (write_helper(it->client.fifo_in, message_length.buff, sizeof(int)) == -1) {
                //TODO: What do we do if writing to the fifo_out failed?
                printf("writing to the fifo_in a public message ERROR1 \n");
                return;
            }
            if (write_helper(it->client.fifo_in, message, message_length.data) == -1) {
                //TODO: What do we do if writing to the fifo_out failed?
                printf("writing to the fifo_in a public message ERROR2 \n");
                return;
            }
            pthread_mutex_unlock(&it->client.fifo_in_lock);
            memset(message, 0, MESSAGE_LENGTH);
            message_length.data = 0;
        }

        if (pthread_create(&thread, NULL, client_handler, &new_client) != 0)
            printf("Couldn't create a thread to listen to the client.... Not ok \n");

        if (pthread_create(&thread, NULL,client_handler1 ,&new_client ) != 0)
            printf("Couldn't create a thread to listen to the client.... Not ok \n");
        print_clients();
    }
}

最佳答案

看起来您正在服务器中的所有线程之间共享一个 new_client 实例。调用 pthread_create() 不会神奇地复制 new_client。所以你创建的每个线程都使用相同的 new_client。因此,当您的主线程为第二个客户端填写值时,处理第一个客户端的线程也会尝试使用这些值。

为每个客户端分配一个新的 new_client,填写值并将其传递给 pthread_create()。 pthread_create() 中的第一个参数还需要一个每个客户端变量。

其他 - 您似乎在客户端和服务器之间传递原始二进制数据,例如字符串长度整数。一旦你不得不开始为不同的操作系统做客户端,这种事情就会给你带来一大堆麻烦。我强烈建议您采用序列化技术,最好是 ASN.1(不是免费但非常强大)或 Google Protocol Buffers(免费但不是那么丰富或强大)。

关于c - 似乎 pthread_create 正在覆盖以前的线程,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20849215/

相关文章:

C - 从单行给出回文列表

使用 union 计算 log2

c++ - LEX:段错误:11

linux - 如何在 linux 中使用 awk 命令获取与特定值匹配的列的记录数

php - 安装package.json

c++ - 如何根据程序的计算需求自动将线程添加到池中?

c - Matrix 中的同时旋转

三个 Shift 键的 Linux 键盘配置 (xkb)

c - 将数组中的元素作为指针传递给 C 中的函数

multithreading - 我如何保证一个线程将比另一个线程长寿,从而允许我在没有“静态”的情况下共享引用?