Как сделать потоки функций безопасными в С++?
Скажем, у меня есть пул потоков, у которого есть 5 дочерних потоков. И они вызывают функцию под названием "functionA()". Как сделать функцию безопасной потоком?
Также, если эти 5 потоков вызывается одновременно, они выполняются одновременно?
или они ждут, пока поток, который в настоящее время работает в функции, будет завершен?
Спасибо заранее.
Ответы
Ответ 1
Функция уже потокобезопасна, если она не изменяет нелокальную память и не вызывает никакой функции. В этом (тривиальном) случае вам ничего не нужно делать.
Вы действительно хотите думать о защите данных, а не о функциях. Например, скажем, что функция изменяет нелокальную структуру данных X. Предоставляет мьютекс для защиты X и блокировки его перед каждым доступом и разблокировать его после. У вас может быть больше, чем une-функция, которая обращается к X (например, insertX(), deleteX(),...). Пока вы защищаете данные, все будет в порядке.
Ответ 2
Вам нужно убедиться, что функция работает одинаково каждый раз, когда она вызывается.
Это обычно означает, что вам необходимо защитить любые данные, которые доступны/записаны в функции.
Для автономных бесплатных функций, которые обычно означают удаление статических элементов из функции.
Если вы ссылаетесь на функцию-член какого-либо класса, то вам нужно быть более осторожным - поскольку класс обычно будет хранить данные независимо от функции-члена, которая может меняться между вызовами этого элемента. Обычно вы делаете это с помощью мьютекса.
Например:
//Threadsafe because the function do not change each time it is called
double add_one(double d)
{
return d+1;
}
struct A
{
double m_data;
//Not thread safe because if function called simultaneously then m_data could change more than once before it is returned
double
run(double d)
{
m_data += d;
return m_data/2.0;
}
}
Это можно устранить, добавив мьютекс, который требует, чтобы два потока не могли одновременно запускать элемент запуска. См. Boost.Thread для хорошего примера мьютекса.
struct A
{
double m_data;
mutex m_mutex;
//Thread safe because mutex protects m_data from being written by multiple threads at once
double
run(double d)
{
lock(m_mutex); //lock the function, unlock on destruction.
m_data += d;
return m_data/2.0;
}
}
Ответ 3
Используя мьютекс, вы можете это сделать.
или:
mutex_lock(&mutex);
functionA();
mutex_unlock(&mutex);
или внутри функции A();
int functionA() {
mutex_lock(&mutex);
// code
mutex_unlock(&mutex);
}
осторожно со вторым решением, потому что если у функции есть другие пути выхода (например, возврат в середине), а мьютекс не разблокирован, у вас есть ситуация, называемая тупиком.
Ответ 4
Один из способов сделать это - использовать мьютекс, чтобы гарантировать, что только один поток выполняет функцию в любой момент времени. Конечно, это предполагает, что это тип безопасности потоков, о котором вы говорите. Быть потокобезопасным может означать много разных вещей. Например, прочитайте сообщение Эрика Липперса под названием Что вы называете "потокобезопасным" ?
Если эти 5 потоков вызывается одновременно, они выполняются одновременно или они ждут, пока поток, который в настоящее время работает в функции, будет завершен?
Если вы не навязываете какой-либо механизм синхронизации (например, mutex), потоки выполняют эту функцию одновременно. Независимо от того, является ли это проблемой для вашей функции и что такое решение, зависит от шаблонов доступа к данным этой функции.
Ответ 5
Это зависит от того, что вы хотите сделать/что вы понимаете под потокобезопасностью.
Обычно вы не хотите, чтобы потоки одновременно обрабатывали одни и те же данные, чтобы вы сериализовали это.
Но это означает, что если один поток находится в функции, все остальные должны ждать. Это называется мьютексом (взаимное исключение).
Другим способом было бы иметь несколько потоков в функции, но ограниченное число.
Там вы можете применить семафор.
Итак, что вы хотите сделать?