好像pthread_create正在覆盖以前的线程

时间:2013-12-30 23:17:54

标签: c linux multithreading pthreads

我正在尝试编写一个IRC类型的聊天客户端,其客户端可以连接到服务器。我试图让它在本地工作(使用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();
    }
}

2 个答案:

答案 0 :(得分:4)

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

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

其他事情 - 您似乎在客户端和服务器之间传递原始二进制数据,比如字符串长度整数。一旦你不得不开始为不同的操作系统做客户,这种事情会让你陷入一大堆痛苦。我强烈建议您采用序列化技术,最好是ASN.1(不是免费但非常强大)或Google协议缓冲区(免费但不富有或强大)。

答案 1 :(得分:1)

if (pthread_create(&thread, NULL,client_handler ,&new_client ) != 0)
...
if (pthread_create(&thread, NULL,client_handler1 ,&new_client ) != 0)

为什么每次都使用相同的pthread_t变量?您不能使用相同的线程变量。更喜欢使用pthread_t这样的数组:

pthread_t thread[2];

if (pthread_create(&thread[0], NULL, client_handler, &new_client ) != 0)
...
if (pthread_create(&thread[1], NULL, client_handler1, &new_client ) != 0)