Передать указатель на переменную в стеке для нового потока - этот код безопасен? - PullRequest
0 голосов
/ 05 мая 2018

Рассмотрим следующий код:

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_connection или wait_for_connection), а был составлен для передачи идеи, поэтому в качестве аргумента, скажем, все функции всегда получается ...
Однако я действительно задаюсь вопросом о том, как использовать локальную переменную в качестве аргумента для вновь созданного потока.
Рассмотрим следующий сценарий:

  1. wait_for_connection принимает новое соединение и возвращает incoming_client_socket.
  2. incoming_client_socket передается "по ссылке" на echo_data во вновь созданном потоке, в то время как в настоящее время он хранится в застрявшем main().
  3. Теперь предположим, что потребуется некоторое время, пока echo_data скопирует данные, обозначенные client_socket, и тем временем основной поток примет другое соединение, которое переполнит предыдущее incoming_client_socket - поток затем скопирует неверные данные .

Это реальная проблема? если нет, то как? Если это так, то какой безопасный способ сделать это?

1 Ответ

0 голосов
/ 05 мая 2018

Это реальная проблема?

Да. Это не безопасный способ сделать это.

Вы можете передать значение напрямую вместо передачи его адреса.

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;
}

Не забудьте освободить память.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...