Правильный способ передачи указателя на другой поток - PullRequest
0 голосов
/ 04 июня 2018

У меня есть 2 функции, func1() и func2().func2 принимает массив символов в качестве входных данных.Обе функции работают в разных потоках.Я звоню func2 с func1.Когда я передал массив, выделенный стеком, в func2, я получил значения мусора, когда печатал массив из func2().Однако, когда я передал массив, выделенный кучей, в func2, я получил правильную строку внутри func2(), то есть

func2(char * char_array)
{
/* Some code */
cout<<char_array;
}

/ * Это не работает (значения мусора были напечатаны в func2 ()) * /

func1()
{
char array_of_char[SIZE];
memset(array_of_char,0,SIZE);
strncpy(array_of_char,"SOME_STRING",SIZE);
func2(array_of_char); //Asynchronous call to func2(). func1() proceeds immediately.
/*
some code
*/
}

/ * Это работает (правильные значения были напечатаны в func2) * /

func1()
{
char * array_of_char=new char[SIZE];
memset(array_of_char,0,SIZE);
strncpy(array_of_char,"SOME_STRING",SIZE);
func2(array_of_char); //Asynchronous call to func2(). func1() proceeds immediately.
/*
some code
*/
}

Означает ли это, что вмногопоточные программы, когда всякий раз указатель должен передаваться между разными потоками, указатель всегда должен указывать на выделенную кучу память?

Обратите внимание, что func2 () на самом деле является функцией обратного вызова, котораявыполняется при наступлении события.Я спрятал эти детали в вопросе.Func1 () не останавливает и не ждет выполнения func2 ().

Edit : я чувствую, что мне нужно предоставить более подробную информацию о моей реализации.В моей программе я использую клиентскую библиотеку Datastax C ++ для Cassandra.Пожалуйста, найдите ссылку в конце, содержащую некоторые детали функций, используемых в программе:

int main()
{

func1();
/* some code */
return 0;
}

/ * Это не работает (мусор печатается в func2) * /

void func1()
{
/* some code */
char array_of_char[SIZE];
memset(array_of_char,0,SIZE);
strncpy(array_of_char,"SOME_STRING",SIZE);
CassFuture* l_query_future = NULL;
/* some code where query is created */
l_query_future = cass_session_execute(rtGetSession(), l_stmt); //l_stmt is the query statement, rtgetSession() returns CassSession *
cass_future_set_callback ( l_query_future, func2, (void *)array_of_char); //details in the link given in the end
/* some code */
}

/ * Это работает (правильные значения были напечатаны в func2) * /

void func1()
{
/* some code */
char * array_of_char=new char[SIZE];
memset(array_of_char,0,SIZE);
strncpy(array_of_char,"SOME_STRING",SIZE);
CassFuture* l_query_future = NULL;
/* some code where query is created */
l_query_future = cass_session_execute(rtGetSession(), l_stmt); //l_stmt is the query statement, rtgetSession() returns CassSession *
cass_future_set_callback ( l_query_future, func2, (void *)array_of_char);
/*
some code
*/
}


void func2(CassFuture* l_query_future, void * data)
{
/* some code */
cout<<(char *)data;
}

Ссылки на API драйвера Datastax:

  1. cass_future_set_callback
  2. CassFuture
  3. CassSession
  4. cass_session_execute

Ответы [ 4 ]

0 голосов
/ 04 июня 2018

Этот код отлично работает с массивом, размещенным в стеке.Как уже упоминалось, здесь не происходит абсолютно никаких потоков.Чтобы ответить на ваш вопрос, однако, при передаче указателей (или других данных) между различными потоками (когда вы на самом деле их используете) вам, вероятно, понадобится какая-то синхронизация, такая как мьютекс или атомарность, и, конечно, обеспечить время жизни любых данных.

Вот ваш рабочий код,

#include <iostream>
#include <cstring>
using namespace std;

#define SIZE 20

void func2(char * char_array)
{
    /* Some code */
    cout<<char_array;
}

void func1()
{
    char array_of_char[SIZE];
    strncpy(array_of_char,"SOME_STRING",SIZE);
    func2(array_of_char);
}

int main() {
    func1();
    return 0;
}

Демонстрация

Я должен заметить, что вы копируете дополнительный мусор путем strncpy'ing SIZE вмассив, вы действительно просто хотите скопировать strlen ("SOME_STRING").

0 голосов
/ 04 июня 2018

Нет, указатель не обязательно должен указывать на выделенную кучу память, но вы должны убедиться, что память (в данном случае - массив) будет доступна, пока вы не присоединитесь к потоку.

Здесь, в версии, которая не работает, массив размещается в стеке, а когда функция func1 завершается, он уничтожается.Следовательно, значения мусора - вероятно, что-то уже записано по этому адресу.

Чтобы обойти это, вы можете подождать, пока поток не завершится в func1.Локальная переменная в этом случае будет в порядке.

0 голосов
/ 04 июня 2018

Как вы запускаете func1 () и func2 () в разных потоках?func1 () напрямую вызывает func2 (), поэтому они запускаются в одном потоке.Даже первая реализация func1 () должна работать, так как массив все еще на своем месте.

EDIT:

Но вызов func2 () напрямую из func1 () не является "асинхронный вызов func2 () "(даже если в какой-то другой момент он используется как функция потока).«Асинхронный вызов» означает создание нового потока с функцией func2 ().Если это так, то такое поведение очень ожидаемо, потому что func1 () мог завершиться при запуске func2 (), и к тому времени массив не существовал.С другой стороны, блок кучи все равно будет выделен, поэтому это будет работать.Затем func2 () должен освободить блок.

EDIT2:

Ммм, да, 2-я версия действительно является "асинхронным вызовом func2 ()", поэтому приведенные выше соображения времени жизни объектовдействительно применимо.

0 голосов
/ 04 июня 2018

Означает ли это, что в многопоточных программах всякий раз, когда какой-либо указатель должен передаваться между различными потоками, указатель всегда должен указывать на выделенную кучу память?

Нет,Это означает, что вы должны правильно отслеживать время жизни ваших объектов.Когда поток 1 завершит выполнение, стек будет автоматически очищен, что испортит результаты, с которыми работает поток 2.Память кучи, с другой стороны, остается, если не освобождена явно.В потоке 1 необходимо проверить, выполняется ли еще поток 2, и дождаться его завершения, например, с помощью функции join.

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