← Назад к вопросам

Каким вызовом создастся новый поток?

1.8 Middle🔥 161 комментариев
#Многопоточность и синхронизация#Язык C++

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI29 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Создание новых потоков в C++

Это фундаментальный вопрос многопоточного программирования. В C++ существует несколько способов создания потоков, в зависимости от версии стандарта и платформы.

1. Стандартная библиотека C++11: std::thread

Это самый современный и рекомендуемый способ. std::thread — часть стандартной библиотеки с C++11.

Создание потока с функцией

#include <thread>
#include <iostream>

void workerFunction(int id) {
    std::cout << "Thread " << id << " is running\n";
}

int main() {
    std::thread t1(workerFunction, 1);
    t1.join();
    std::cout << "Thread completed\n";
    return 0;
}

Создание с лямбда-функцией

#include <thread>
#include <iostream>

int main() {
    int id = 42;
    std::thread t([id]() {
        std::cout << "Lambda thread with id = " << id << std::endl;
    });
    t.join();
    return 0;
}

Создание с методом класса

#include <thread>
#include <iostream>

class Worker {
public:
    void doWork(int id) {
        std::cout << "Worker thread " << id << " running\n";
    }
};

int main() {
    Worker worker;
    std::thread t(&Worker::doWork, &worker, 1);
    t.join();
    return 0;
}

2. POSIX потоки (pthread)

Это низкоуровневый API, используется в системном программировании. Работает на Unix/Linux.

#include <pthread.h>
#include <iostream>

void* threadFunction(void* arg) {
    int* id = (int*)arg;
    std::cout << "POSIX thread " << *id << " running\n";
    delete id;
    return nullptr;
}

int main() {
    pthread_t thread1;
    int* threadId = new int(1);
    int result = pthread_create(&thread1, nullptr, threadFunction, threadId);
    
    if (result != 0) {
        std::cerr << "Error creating thread\n";
        return 1;
    }
    pthread_join(thread1, nullptr);
    return 0;
}

3. Windows API: CreateThread

Для Windows систем, даёт больше контроля.

#include <windows.h>
#include <iostream>

DWORD WINAPI ThreadFunction(LPVOID param) {
    int* id = (int*)param;
    std::cout << "Windows thread " << *id << " running\n";
    delete id;
    return 0;
}

int main() {
    HANDLE hThread;
    int* threadId = new int(1);
    hThread = CreateThread(
        nullptr,
        0,
        ThreadFunction,
        threadId,
        0,
        nullptr
    );
    
    if (hThread == nullptr) {
        std::cerr << "Error creating thread\n";
        return 1;
    }
    WaitForSingleObject(hThread, INFINITE);
    CloseHandle(hThread);
    return 0;
}

4. Управление потоками

join() vs detach()

#include <thread>
#include <chrono>
#include <iostream>

int main() {
    std::thread t1([]() {
        std::this_thread::sleep_for(std::chrono::seconds(2));
        std::cout << "Thread 1 finished\n";
    });
    
    std::thread t2([]() {
        std::cout << "Thread 2 starting\n";
    });
    
    t1.join();    // Блокирует, ждет завершения
    t2.join();    // Ждем t2
    
    return 0;
}

join() — блокирует вызывающий поток до завершения целевого потока detach() — отделяет поток, он работает независимо

Синхронизация потоков

#include <thread>
#include <mutex>
#include <iostream>

std::mutex m;
int sharedData = 0;

void incrementData() {
    std::lock_guard<std::mutex> lock(m);
    sharedData++;
    std::cout << "Data: " << sharedData << std::endl;
}

int main() {
    std::thread t1(incrementData);
    std::thread t2(incrementData);
    std::thread t3(incrementData);
    
    t1.join();
    t2.join();
    t3.join();
    
    return 0;
}

5. Частые ошибки

Забыли join/detach

// НЕПРАВИЛЬНО!
int main() {
    std::thread t([]() {
        std::cout << "Thread running\n";
    });
    return 0;  // Программа завершится, поток будет убит
}

// ПРАВИЛЬНО:
int main() {
    std::thread t([]() {
        std::cout << "Thread running\n";
    });
    t.join();  // Ждём завершения
    return 0;
}

Захват по ссылке в лямбда

// НЕПРАВИЛЬНО!
int main() {
    int x = 42;
    std::thread t([&x]() {  // Захват по ссылке опасен
        std::cout << x << std::endl;
    });
    return 0;  // x может быть удалена до выполнения потока
}

// ПРАВИЛЬНО:
int main() {
    int x = 42;
    std::thread t([x]() {   // Захват по значению
        std::cout << x << std::endl;
    });
    t.join();
    return 0;
}

6. RAII pattern для потоков

class ThreadGuard {
    std::thread t;
public:
    ThreadGuard(std::thread&& thread) : t(std::move(thread)) {}
    ~ThreadGuard() {
        if (t.joinable()) t.join();
    }
    ThreadGuard(const ThreadGuard&) = delete;
    ThreadGuard& operator=(const ThreadGuard&) = delete;
};

int main() {
    ThreadGuard tg(std::thread([]() {
        std::cout << "Safe thread execution\n";
    }));
    return 0;  // Автоматически join'ится
}

Сравнение способов

СпособЯзыкПлатформаУровеньКогда использовать
std::threadC++11+Кросс-платформаВысокийВсегда (рекомендуется)
pthreadCUnix/LinuxСреднийСистемное ПО, legacy код
CreateThreadC++WindowsСреднийWindows-специфика

Best Practices

  1. Всегда используй std::thread для новых проектов
  2. Всегда вызывай join() или detach() — иначе программа упадёт
  3. Используй RAII для автоматического управления потоками
  4. Синхронизируй общие данные с помощью mutex
  5. Избегай захвата по ссылке в лямбда для потоков
  6. Передавай параметры напрямую конструктору std::thread, не захватывай переменные

Вывод: Для современного C++ (C++11 и выше) используй std::thread. Это кросс-платформенный, безопасный и удобный способ создания потоков. Помни о RAII и синхронизации!