将指针传递给新线程的堆栈变量 - 这段代码安全吗?

时间:2018-05-05 08:46:46

标签: c networking pthreads

请考虑以下代码:

void* echo_data(void* client_socket) {
    // for the sake of argument - suppose there's a lot of code here before we copy the socket to local variable:
    int socket = *(int*)client_socket;
    // send back whatever is coming from client
    return (void*)0;
}

int main(int argc, char* argv[]) {
    int server_socket = establish_connection();

    while (1) {
        int incoming_client_socket = wait_for_connection(server_socket);
        fprintf(stdout, "new connection accepted...\n");

        pthread_t client_thread;
        pthread_create(&client_thread, NULL, echo_data, (void*)&incoming_client_socket);
    }
}

我知道我在这里忽略了返回代码,但是这段代码实际上没有运行(没有establish_connectionwait_for_connection)并且汇总在一起传达一个想法,所以为了论证,我们说所有的功能总是成功的...
但是,我确实特别想知道使用局部变量作为新创建线程的参数的含义 请考虑以下情形:

  1. wait_for_connection接受新连接并返回incoming_client_socket
  2. incoming_client_socket通过"参考"到新创建的帖子中的echo_data,当前它存储在main()卡住了。
  3. 现在假设echo_data复制client_socket指向的数据需要一些时间,同时主线程接受另一个连接,这将超出之前的incoming_client_socket - 然后该线程会复制错误的数据。
  4. 这真的是一个问题吗? 如果没有,怎么样? 如果是这样,那么这样做是否安全?

1 个答案:

答案 0 :(得分:2)

  

这真的是一个问题吗?

是。它不是一种安全的方式。

您可以直接传递值,而不是传递其地址。

pthread_create(&client_thread, NULL, echo_data, (void*) incoming_client_socket);`

并且线程函数应该像

void* echo_data(void* client_socket) {
  int socket = (int)client_socket;
  /* your code */
}

如果你希望将多个元素传递给线程,那么你可以将它包装在一个结构中,为它创建一个结构指针,分配内存并填充值并将指针传递给线程。

struct X {
  int socket;
  /* other members here*/
};

  while (1) {
    int incoming_client_socket = wait_for_connection(server_socket);
    fprintf(stdout, "new connection accepted...\n");
    struct X *ptr = malloc (sizeof(struct X));
    ptr->socket = incoming_client_socket;
    /* other assignment here */

    pthread_create(&client_thread, NULL, echo_data, (void*)ptr);
  }

你的线程函数应该看起来像

void* echo_data(void* client_socket) {
  // for the sake of argument - suppose there's a lot of code here before we copy the socket to local variable:
  struct X *ptr = (struct X *)client_socket;
  // send back whatever is coming from client
  return (void*)0;
}

不要忘记释放记忆。