1. Не понял пока зачем тут нужен mutex, но да ладно, пусть будет. Но ты неправильно тут юзаешь mutex. Ты каждый вызов функции создаешь новый локальный mutex, это не имеет смысла. Должен быть один общий mutex на все вызовы, тогда и блокировка будет корректно работать по этому mutex'у.
2. Непонятно зачем ты сразу делаешь detach(). Ты таким образом ничего не получаешь кроме потери контроля над потоком. Попробуй наоборот, контролировать поток до конца. Создай хранилище указателей на созданные потоки и только при detach’е либы убедись что все они завершены.
// Допустим есть статичное хранилище потоков, с его инициализацией думаю разберешься
static std::vector<std::thread*> my_threads;
// ...
// создавай потоки так
my_threads.push_back(new std::thread(func));
// ...
// при выгрузке либы делай так
// пока в хранилище есть потоки
while(!my_threads.empty())
{
// получаем какой-то поток
auto th = my_threads.back();
// ждем его завершения
th->join();
// удаляем объект потока
delete th;
// удаляем из хранилища
my_threads.pop_back();
}
По идее все join'ы должны почти без блокировки закрываться, если все http запросы в потоках завершились нормально и не остались висеть.