Коль уж встал вопрос о кросс-платформенной многопоточности, и коль уж новый стандарт языка её поддерживает, стоит иметь под рукой пример её использования:
Классика жанра: "Обедающие философы"
#include <cstdlib>
#include <ctime>
#include <exception>
#include <iostream>
#include <mutex>
#include <thread>
#include <vector>
using namespace std;
// FORK ////////////////////////////////////////////////////////////////////////
class Fork
{
        friend bool tryToTake(Fork &fork);
        friend void release(Fork &fork);
private:
        timed_mutex _mutex;
        int _number;
public:
        Fork(const int number) :
                _mutex(),
                _number(number)
        {}
        int number() const
        {
                return _number;
        }
};
bool tryToTake(Fork &fork)
{
        return fork._mutex.try_lock_for(chrono::milliseconds(0));
}
void release(Fork &fork)
{
        fork._mutex.unlock();
}
// PHILOSOPHIER ////////////////////////////////////////////////////////////////
class Philosophier
{
private:
        class Implementation
        {
        private:
                enum State
                {
                        Eat,
                        Relax,
                        Wait
                };
                Fork &_leftFork;
                Fork &_rightFork;
                int _number;
                volatile bool _finalize;
                State _state;
                bool _tryToTake(Fork &fork)
                {
                        bool result = tryToTake(fork);
                        if(result)
                        {
                                cout << "Philosophier " << _number << " has taken fork " << fork.number() << "." <<  endl;
                        }
                        else
                        {
                                cout << "Philosophier " << _number << " hasn't taken fork " << fork.number() << "." <<  endl;
                        }
                        return result;
                }
                void _release(Fork &fork)
                {
                        release(fork);
                        cout << "Philosophier " << _number << " has released fork " << fork.number() << "." << endl;
                }
                void _action(const int timeout)
                {
                        switch(_state)
                        {
                        case Relax:
                        case Wait:
                                {
                                        bool leftResult = _tryToTake(_leftFork);
                                        bool rightResult = _tryToTake(_rightFork);
                                        if(leftResult && rightResult)
                                        {
                                                cout << "Philosophier " << _number << " is eating " << timeout << " times." << endl;
                                                _state = Eat;
                                        }
                                        else
                                        {
                                                if(leftResult)
                                                {
                                                        _release(_leftFork);
                                                }
                                                if(rightResult)
                                                {
                                                        _release(_rightFork);
                                                }
                                                cout << "Philosophier " << _number << " is waiting " << timeout << " times." << endl;
                                                _state = Wait;
                                        }
                                }
                                break;
                        case Eat:
                                {
                                        _release(_leftFork);
                                        _release(_rightFork);
                                        cout << "Philosophier " << _number << " is relaxed " << timeout << " times." << endl;
                                        _state = Relax;
                                }
                                break;
                        default:
                                throw exception();
                        }
                }
        public:
                Implementation(const int number, Fork &leftFork, Fork &rightFork) :
                        _number(number),
                        _leftFork(leftFork),
                        _rightFork(rightFork),
                        _finalize(false),
                        _state(Relax)
                {}
                void operator()()
                {
                        cout << "Philosophier " << _number << " began." << endl;
                        while(!_finalize)
                        {
                                int timeout = rand() % 5 + 1;
                                _action(timeout);
                                this_thread::sleep_for(chrono::seconds(timeout));
                        }
                        cout << "Philosophier " << _number << " ended." << endl;
                }
                void finalize()
                {
                        _finalize = true;
                }
        };
        Implementation _implementation;
        thread _thread;
public:
        Philosophier(const int number, Fork &leftFork, Fork &rightFork) :
                _implementation(number, leftFork, rightFork),
                _thread(ref(_implementation))
        {}
        ~Philosophier()
        {
                _implementation.finalize();
                _thread.join();
        }
};
// MAIN ////////////////////////////////////////////////////////////////////////
int main()
{
        srand(time(NULL));
        cout << "Press Enter for exit." << endl;
        
        vector<Fork *> forks;
        vector<Philosophier *> philosophiers;
        const int n = 3;
        Fork *firstFork = new Fork(1), *previousFork = firstFork;
        forks.push_back(previousFork);
        for(int i = 0; i < n; ++i)
        {
                Fork *nextFork;
                if(i < n - 1)
                {
                        nextFork = new Fork(i + 2);
                        forks.push_back(nextFork);
                }
                else
                {
                        nextFork = firstFork;
                }
                Philosophier *philosophier = new Philosophier(i + 1, *previousFork, *nextFork);
                philosophiers.push_back(philosophier);
                previousFork = nextFork;
        }
        
        getchar();
        for(int i = 0; i < philosophiers.size(); ++i)
        {
                delete philosophiers[i];
        }
        for(int i = 0; i < forks.size(); ++i)
        {
                delete forks[i];
        }
        return 0;
}
Вкратце основные положения:
- Запуск потока происходит путём создания объекта класса std::thread (файл <thread>).
- В качестве тела потока (и аргумента конструктора thread) может выступать любой функтор: как обычная функция, так и объект с перегруженными оператором (). Функтор может иметь произвольную сигнатуру - любое количество параметров любых типов, библиотека это успешно переваривает. Аргументы функтора передаются как опциональные параметры thread сразу после самого функтора.
- (Важно!) Все аргументы thread - как сам функтор, если это объект, так и передаваемые функтору аргументы - передаются по значению, а не по ссылке. Поэтому всегда происходит полное копирование всех переданных аргументов в контекст нового потока. Если в качестве функтора нужно передать конкретный объект, а не его копию, функтор нужно обернуть в объект std::ref() - см. в коде.
- Синхронизация потоков происходит при вызове у потока метода join() - дожидаемся завершения интересующего нас потока и двигаемся дальше. Любопытна трансляция исключений. Так, если поток умер по некоему необработанному исключению, это будет злопамятно сохранено, и тот поток, который вызовет join - тот и получит это исключение от умершего потока. Так что join надо вызывать с опаской, чтобы не получить по лбу.
- Поток можно сделать зомби, вызвав у объекта потока метод detach. А всё потому, что нет сборщика мусора. Поэтому деструктор объекта thread принудительно убивает поток. Поэтому локальная переменная потока, выходящая из области видимости, приводит к срыву работы. Чтобы этого не происходило, нужно делать detach. Извращение. Я бы заставил хранить объект потока до победы, ибо нечего зомби разводить в системе - считай, аналог утечки памяти.
- Глобальная переменная std::this_thread есть объект текущего потока в контексте каждого потока. Кстати говоря, появилось служебное слово thread_local для переменных, которые не локальные, но и не глобальные как static. Т.е. глобальны в контексте потока. Это ещё одно извращение, поскольку всегда можно обеспечить нужный уровень локальности соответствующим объектом.
- У std::this_thread есть метод sleep_for для засыпания потока на таймаут. Вообще, впечатление такое, что в общем случае методы *_for работают с интервалами времени, а методы *_until работают до наступления определённого момента календарного времени. Но в подробности я ещё не погружался.
- Есть некий элемент std::chrono (даже не знаю, класс это или пространство имён), в котором сосредоточены всякие разности для работы со временем. Так chrono::milliseconds и chrono::seconds описывают интервалы времени в соответствующих единицах. Но там есть и точки календарного времени и прочее всякое разное.
- Объекты синхронизации представлены разными мьютексами и условными переменными (файл <mutex>). Но поскольку в подавляющем большинстве случаев достаточно мьютекса (как семафора со счётчиком 1), на нём и остановимся.
- Есть в доску простой std::mutex с методами lock и unlock. Тут и комментировать особо нечего.
- Есть мьютекс с таймаутом std::timed_mutex, у которого в дополнение к простому мьютексу есть методы try_lock_for и try_lock_until с аргументами из chrono с вышеописанной смысловой разницей. Возвращают эти методы bool, означающий успех или неуспех блокировки.
- Есть всякие другие мьютексы, и возможности установки/снятия блокировки по bool-выражению, чтобы исключить гонку. Есть объекты для критических секций. Есть возможность блокировки групп мьютексов. Но до этого руки ещё не дошли.