← Назад к вопросам
Может ли быть в одном процессе несколько потоков?
1.3 Junior🔥 191 комментариев
#Многопоточность и синхронизация
Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI21 мар. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
# Несколько потоков в одном процессе
Да, абсолютно — один процесс может содержать множество потоков (threads). Это фундаментальная концепция многопоточного программирования.
Архитектура процесса и потоков
Однопоточный процесс
Процесс P1
├─ Виртуальное адресное пространство (4GB or 64GB)
│ ├─ Code segment (исполняемый код)
│ ├─ Data segment (глобальные переменные)
│ ├─ Heap (динамическая память)
│ └─ Stack (локальные переменные)
├─ PID (Process ID)
├─ File descriptors (открытые файлы)
├─ Environment variables
└─ Thread 1 (main)
├─ Собственный Stack
├─ Регистры CPU
└─ Thread-local storage (TLS)
Многопоточный процесс
Процесс P1
├─ Виртуальное адресное пространство (ОБЩЕЕ для всех потоков)
│ ├─ Code segment
│ ├─ Data segment
│ ├─ Heap (ОБЩАЯ память)
│ └─ Stacks區域
├─ PID
├─ File descriptors
├─ Environment variables
└─ НЕСКОЛЬКО потоков:
├─ Thread 1 (main)
│ ├─ Stack 1
│ ├─ Регистры TID=1001
│ └─ TLS 1
├─ Thread 2 (worker)
│ ├─ Stack 2
│ ├─ Регистры TID=1002
│ └─ TLS 2
└─ Thread 3 (worker)
├─ Stack 3
├─ Регистры TID=1003
└─ TLS 3
Что разделяют потоки?
Все потоки внутри одного процесса разделяют:
#include <thread>
#include <iostream>
#include <vector>
int global_var = 42; // ✅ РАЗДЕЛЯЕМО: все потоки видят одну переменную
int main() {
std::vector<int> shared_data = {1, 2, 3}; // ✅ РАЗДЕЛЯЕМО
auto thread_func = [&] {
std::cout << global_var << "\n"; // ✅ видит 42
std::cout << shared_data[0] << "\n"; // ✅ видит 1
global_var = 100; // ✅ изменит для всех!
shared_data[0] = 999; // ✅ изменит для всех!
};
std::thread t(thread_func);
t.join();
std::cout << global_var << "\n"; // Выведет 100
std::cout << shared_data[0] << "\n"; // Выведет 999
return 0;
}
Что уникально для каждого потока?
int main() {
std::thread t1([] {
int local_var = 10; // ❌ НЕ разделяется — свой stack
static int static_var; // ✅ РАЗДЕЛЯЕТСЯ (в data segment)
thread_local int tls_var; // ✅ РАЗДЕЛЯЕТСЯ (но у каждого свой экземпляр)
});
std::thread t2([] {
int local_var = 20; // Другой local_var, другой адрес в памяти
});
t1.join();
t2.join();
}
Практический пример: Server с многопоточностью
class WebServer {
private:
std::vector<std::thread> worker_threads; // пул потоков
std::queue<Request> request_queue; // ✅ РАЗДЕЛЯЕМАЯ очередь
std::mutex queue_mutex; // синхронизация доступа
std::condition_variable cv; // уведомление потоков
bool shutdown = false; // флаг для всех потоков
public:
WebServer(int num_workers) {
for (int i = 0; i < num_workers; ++i) {
// Запускаем несколько потоков в одном процессе
worker_threads.emplace_back([this] {
worker_loop();
});
}
}
void worker_loop() {
while (true) {
std::unique_lock<std::mutex> lock(queue_mutex);
// Ждём, пока придёт запрос
cv.wait(lock, [this] {
return !request_queue.empty() || shutdown;
});
if (shutdown && request_queue.empty()) break;
Request req = request_queue.front(); // ✅ читаем из общей очереди
request_queue.pop();
lock.unlock();
// Обрабатываем запрос (этот код выполняется параллельно!)
Response resp = handle_request(req);
send_response(resp);
}
}
void handle_incoming_request(Request req) {
std::unique_lock<std::mutex> lock(queue_mutex);
request_queue.push(req); // ✅ пишем в общую очередь
lock.unlock();
cv.notify_one(); // пробуждаем одного worker'а
}
~WebServer() {
{
std::lock_guard<std::mutex> lock(queue_mutex);
shutdown = true;
}
cv.notify_all(); // пробуждаем всех worker'ов
for (auto& t : worker_threads) {
t.join(); // ждём завершения всех потоков
}
}
};
Создание и управление потоками
#include <thread>
#include <chrono>
// Функция для потока
void worker(int id, int delay_ms) {
std::cout << "Thread " << id << " started\n";
std::this_thread::sleep_for(std::chrono::milliseconds(delay_ms));
std::cout << "Thread " << id << " finished\n";
}
int main() {
// Создаём несколько потоков
std::vector<std::thread> threads;
for (int i = 1; i <= 5; ++i) {
threads.emplace_back(worker, i, i * 100);
// Каждый поток выполняется ПАРАЛЛЕЛЬНО
}
std::cout << "Main thread: created " << threads.size() << " threads\n";
// Ждём завершения всех потоков
for (auto& t : threads) {
t.join();
}
std::cout << "All threads completed\n";
return 0;
}
// Вывод (порядок может варьироваться):
// Main thread: created 5 threads
// Thread 1 started
// Thread 2 started
// Thread 3 started
// Thread 4 started
// Thread 5 started
// Thread 1 finished
// Thread 2 finished
// ...
// All threads completed
Проблемы при наличии нескольких потоков
Race condition
int counter = 0; // ✅ разделяемая переменная
void increment() {
for (int i = 0; i < 1000000; ++i) {
counter++; // ❌ RACE CONDITION!
// Операция не атомарная:
// 1. Load counter в регистр
// 2. Increment регистра
// 3. Store обратно в counter
// Потоки могут перекрываться!
}
}
int main() {
std::thread t1(increment);
std::thread t2(increment);
t1.join();
t2.join();
std::cout << counter << "\n"; // Может быть меньше 2000000!
}
// Решение: atomic
std::atomic<int> counter = 0;
void increment() {
for (int i = 0; i < 1000000; ++i) {
counter++; // ✅ Атомарная операция
}
}
Deadlock
std::mutex mutex_a, mutex_b;
void thread1_func() {
std::lock_guard<std::mutex> lock_a(mutex_a);
std::this_thread::sleep_for(std::chrono::milliseconds(100));
std::lock_guard<std::mutex> lock_b(mutex_b); // ждёт mutex_b
}
void thread2_func() {
std::lock_guard<std::mutex> lock_b(mutex_b);
std::this_thread::sleep_for(std::chrono::milliseconds(100));
std::lock_guard<std::mutex> lock_a(mutex_a); // ждёт mutex_a
}
int main() {
std::thread t1(thread1_func);
std::thread t2(thread2_func);
t1.join(); // ❌ DEADLOCK — потоки ждут друг друга вечно
t2.join();
}
Преимущества многопоточности
// ❌ Однопоточно: одно за другим
void process_sequential() {
for (int i = 0; i < 1000000; ++i) {
fetch_data(i); // 100ms
process_data(i); // 50ms
save_data(i); // 100ms
// 1 итерация = 250ms
// 1000000 итераций = 250M ms = ~70 часов
}
}
// ✅ Многопоточно: параллельно
void process_parallel() {
std::thread fetcher([this] {
for (int i = 0; i < 1000000; ++i) {
fetch_data(i);
}
});
std::thread processor([this] {
for (int i = 0; i < 1000000; ++i) {
process_data(i);
}
});
std::thread saver([this] {
for (int i = 0; i < 1000000; ++i) {
save_data(i);
}
});
fetcher.join();
processor.join();
saver.join();
// 3 итерации параллельно = max(100, 50, 100) = 100ms
// 1000000 итераций = 100M ms = ~28 часов (!!)
}
Ограничения
// Сколько потоков может быть?
int max_threads = std::thread::hardware_concurrency(); // обычно = кол-во ядер
std::cout << "CPU cores: " << max_threads << "\n";
// Но можно создать МНОГО больше (хотя это медленно):
for (int i = 0; i < 10000; ++i) {
std::thread t([] { std::this_thread::sleep_for(std::chrono::seconds(10)); });
t.detach(); // потоки работают независимо (опасно!)
}
// Linux создаст 10000 потоков, но переключение контекста замедлит все
Резюме
Да, один процесс может содержать множество потоков.
Основные моменты:
- Разделяют: код, глобальные переменные, heap, файлы, PID
- Не разделяют: stack, регистры, TLS (thread-local storage)
- Выполняются параллельно (на многоядерных системах) или чередуются (на одноядерных)
- Требуют синхронизации (mutexes, condition variables, atomic)
- Опасны: race conditions, deadlocks, используй инструменты для отладки (ThreadSanitizer)
Современные backend системы используют множество потоков для обработки параллельных запросов, асинхронных операций и масштабирования на мультиядерных ЦПУ.