Передача const char* между областями видимости функций разных потоков (C++)
Назрел довольно странный вопрос.
Допустим, где-то в коде я создаю C-строку const char* szSomeStr = "Some Str", она даже может быть параметром какой-либо функции в которой я передаю эту строку куда-то дальше:
void someFunction(const char* szParam)
{
anotherFunction(szParam)
}
И поскольку в данном случае не происходит выделения памяти и строка нигде не копируется, то все работает быстро.
Но что если мне нужно, например, чтобы функция someFunction запустила anotherFunction в другом потоке:
void someFunction(const char* szParam)
{
m_cThread = std::thread([&](){
anotherFunction(szParam)
});
m_cThread.detach()
}
В таком случае, если я все правильно понимаю, функция someFunction завершается, значение szParam становится не определено, в то время как anotherFunction запущенное в отдельном потоке все еще может его использовать (покуда не завершится лямбда потока).
Такой проблемы бы не было, если бы я, скопировал в отдельном потоке строку и использовал бы её.
void someFunction(const char* szParam)
{
m_cThread = std::thread([&](){
std::string str(szParam);
anotherFunction(str.c_str())
});
m_cThread.detach()
}
Также, если внутри самого потока буду передавать литерал строки, тоже не возникнет проблем:
void someFunction(const char* szParam)
{
m_cThread = std::thread([&](){
anotherFunction("Some string")
});
m_cThread.detach()
}
Но мне нужно кое что другое. Мне нужно как бы "переместить" константную C-строку "между потоками". То есть, чтобы когда я, например, пишу someFunction("MyCoolString"), компилятор счел будто бы я вызываю функцию, тело которой:
{
m_cThread = std::thread([&](){
anotherFunction("MyCoolString")
});
m_cThread.detach()
}
То есть, чтобы эта константная строка как бы "переместилась" в область видимости того потока, и не потерялась, даже когда завершится функция someFunction, при этом оставшись обычной константной строкой.
Есть ли вообще в C++ какая-то такая возможность (макросы не предлагать) в стандарте? Или это не может быть возможным в силу статической природы const char*?
UPD:
Провел небольшой эксперимент, и остался немного удивлен поведением const char*.
std::thread g_cThread;
void firstFunction()
{
// Указатель на строку
const char* szSomeString = "Some text";
// Переменная
const int a = 5;
// Вывод адресов переменной и строки
std::cout << reinterpret_cast<uintptr_t>(&a) << std::endl;
std::cout << reinterpret_cast<uintptr_t>(szSomeString) << std::endl;
// Запускаем поток (передаем на этот раз по значению)
g_cThread = std::thread([=](){
// Ожидаем секунду
std::this_thread::sleep_for(std::chrono::seconds(1));
// Вывод адресов переменной и строки
std::cout << reinterpret_cast<uintptr_t>(&a) << std::endl; // Другой адрес (копирование самих данных)
std::cout << reinterpret_cast<uintptr_t>(szSomeString) << std::endl; // Тот же адрес (копирование указателя)
// Вывод строки по СТАРОМУ адресу, данные которой должны быть уничтожены (работает?!)
std::cout << szSomeString << std::endl;
});
g_cThread.detach();
}
int main([[maybe_unused]] int arc, [[maybe_unused]] char* argv[])
{
// Функция запускает поток
firstFunction();
// Функция завершается (уничтожая созданные внутри объекты) Ждем немного в основном потоке
std::this_thread::sleep_for(std::chrono::seconds(2));
return 0;
}
По каким-то причинам ДАННЫЕ не уничтожаются после завершения функции. То есть const char* ведет себя не так как обычные переменные, а как new char[] (то есть данные глобальны). Или я не прав?
Но не знаю, говорит ли это о том, что я могу безопасно передавать по значению такие строки между потоками и не париться о копировании ДАННЫХ (дабы их не потерять). А также не понятно что будет, если такая строка будет передаваться из одной DLL в другую (где вторая еще ее передаст в какой-ниубдь другой поток)..
Ответы (1 шт):
void someFunction(const char* szParam)
{
m_cThread = std::thread([&](){
anotherFunction(szParam)
});
m_cThread.detach()
}
В таком случае, если я все правильно понимаю, функция someFunction завершается, значение szParam становится не определено, в то время как anotherFunction запущенное в отдельном потоке все еще может его использовать.
Не совсем правильно. Да функция завершается, но у самой строки (массива char) "Some Str" глобальное время жизни - пока работает программа. Переменная, которая является указателем szParam становится не определена, но Вы уже передали адрес строки в другой поток. И таким образом Вы дали другому потоку доступ к константной строке "Some Str". По стандарту константные объекты - потокобезопасны, т.е. читать их можно из нескольких потоков