- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
I have coded a custom concurrent queue class and a thread pool class based on it. I have an "advisor" class that I use to expose the Threadpool class (mixed with other functionalities) to more high level code. (These other functionalities are not included as they are not even the ones triggering the crash.)
The code for the concurrent queue is in the header "concurrent_queue.h" :
#ifndef CONCURRENT_QUEUE_H
#define CONCURRENT_QUEUE_H
#include <queue>
#include <mutex>
#include <optional>
template <class T>
class concurrent_queue
{
std::queue<T> queue_;
std::mutex mutex_;
std::condition_variable cv_;
bool interrupt_;
public:
concurrent_queue() : interrupt_(false) {}
// Pop into argument
std::optional<T> try_pop()
{
std::optional<T> result;
// Lock
std::lock_guard<std::mutex> lok(mutex_);
if (!queue_.empty())
{
// Move from queue
result = move(queue_.front());
// Combine front/pop
queue_.pop();
}
return result;
}
// Pass t byVal or move with push( move( t))
void push(T t)
{
{
// Lock
std::lock_guard<std::mutex> lk(mutex_);
// Move into queue
queue_.push(move(t));
} // Unlock before notification
// Unlock before notification
cv_.notify_one();
}
// Wait if empty
std::optional<T> pop()
{
std::optional<T> result;
// (Unique) lock
std::unique_lock<std::mutex> lk(mutex_);
// Wait if empty, release lock until notified
cv_.wait(lk, [&] { return interrupt_ || !queue_.empty(); });
// Re-acquire lock, resume
// Check for interruption
if (!interrupt_) {
result = std::move(queue_.front());
queue_.pop();
}
return result;
}// Unlock
void interrupt()
{
{
std::lock_guard<std::mutex> lk(mutex_);
interrupt_ = true;
}
cv_.notify_all();
}
void reset_interrupt()
{
interrupt_ = false;
}
void clear()
{
std::queue<T> empty;
swap(queue_, empty);
}
};
#endif//CONCURRENT_QUEUE_H
and the one for the thread pool is in the header "ThreadPool.h" :
#ifndef THREAD_POOL_H
#define THREAD_POOL_H
#include <future>
#include <thread>
#include "concurrent_queue.h"
#include <chrono>
class ThreadPool
{
public:
using Task = std::packaged_task<bool(void)>;
using TaskHandle = std::future<bool>;
private:
// The one and only instance
static ThreadPool instance_;
// The task queue
concurrent_queue<Task> concurrent_queue_;
// The threads
std::vector<std::thread> threads_;
// Active indicator
bool is_active_;
// Interruption indicator
bool interrupt_;
// Thread number
static thread_local size_t my_tls_num_;
// The function that is executed on every thread
void threadFunc(const size_t num)
{
my_tls_num_ = num;
// "Infinite" loop, only broken on destruction
while (auto t = concurrent_queue_.pop())
{
(*t)();
}
}
// The constructor stays private, ensuring single instance
ThreadPool() : is_active_(false), interrupt_(false) {}
public:
// Access the instance
static ThreadPool* getInstance() { return &instance_; }
// Number of threads
size_t numThreads() const { return threads_.size(); }
// The number of the caller thread
static size_t threadNum() { return my_tls_num_; }
// Starter
void start(const size_t nThread = std::thread::hardware_concurrency() - 1)
{
if (!is_active_) // Only start once
{
threads_.reserve(nThread);
// Launch threads on threadFunc and keep handles in a vector
for (size_t i = 0; i < nThread; i++)
threads_.push_back(std::thread(&ThreadPool::threadFunc, this, i + 1));
is_active_ = true;
}
}
//dtor
~ThreadPool()
{
stop();
}
void stop()
{
if (is_active_)
{
// Interrupt mode
interrupt_ = true;
// Interrupt all waiting threads
concurrent_queue_.interrupt();
// Wait for them all to join
for_each(threads_.begin(), threads_.end(), std::mem_fn(&std::thread::join));
// Clear all threads
threads_.clear();
// Clear the queue and reset interrupt
concurrent_queue_.clear();
concurrent_queue_.reset_interrupt();
// Mark as inactive
is_active_ = false;
// Reset interrupt
interrupt_ = false;
}
}
// Forbid copies etc
ThreadPool(const ThreadPool& rhs) = delete;
ThreadPool& operator=(const ThreadPool& rhs) = delete;
ThreadPool(ThreadPool&& rhs) = delete;
ThreadPool& operator=(ThreadPool&& rhs) = delete;
// Spawn task
template<typename Callable>
TaskHandle spawnTask(Callable c)
{
Task t(std::move(c));
TaskHandle f = t.get_future();
concurrent_queue_.push(std::move(t));
return f;
}
// Run queued tasks synchronously
// while waiting on a future,
// returns true if at least one task was run
bool activeWait(const TaskHandle& f)
{
using namespace std::chrono_literals;
bool b = false;
// Check whether or not the future is ready without blocking
// by waiting 0 seconds and returning status
while (f.wait_for(0s) != std::future_status::ready)
{
// Non blocking
if (auto t = concurrent_queue_.try_pop())
{
(*t)();
b = true;
}
else // Nothing in the queue: go to sleep
{
f.wait();
}
}
return b;
}
};
inline ThreadPool ThreadPool::instance_;
inline thread_local size_t ThreadPool::my_tls_num_ = 0;
#endif//THREAD_POOL_H
The code for the Advisor class is in the heard "Advisor.h" :
#ifndef ADVISOR_H
#define ADVISOR_H
#include <mutex>
#include "ThreadPool.h"
class Advisor
{
private:
static Advisor * pinstance_;
static std::mutex mutex_;
protected:
Advisor(const size_t nThread = std::thread::hardware_concurrency() - 1)
{
ThreadPool::getInstance()->start(nThread);
}
virtual ~Advisor()
{
ThreadPool::getInstance()->stop();
}
public:
Advisor(const Advisor& rhs) = delete;
Advisor& operator=(const Advisor& rhs) = delete;
Advisor(Advisor&& rhs) = delete;
Advisor& operator=(Advisor&& rhs) = delete;
static Advisor* GetInstance(const size_t nThread = std::thread::hardware_concurrency() - 1);
};
/**
* Static methods should be defined outside the class.
*/
Advisor* Advisor::pinstance_{ nullptr };
std::mutex Advisor::mutex_;
/**
* The first time we call GetInstance we will lock the storage location
* and then we make sure again that the variable is null and then we
* set the value. RU:
*/
Advisor* Advisor::GetInstance(const size_t nThread)
{
std::lock_guard<std::mutex> lock(mutex_);
if (pinstance_ == nullptr)
{
pinstance_ = new Advisor(nThread);
}
return pinstance_;
}
#endif//ADVISOR_H
and finally the "client" code is :
#include <iostream>
#include "Advisor.h"
static Advisor* pricingAdvisorSingleton = Advisor::GetInstance();
int main()
{
std::cout << "Ok!\n";
}
The coded I attach is a zipped visual studio 2022 professional C++ console app solution folder. The solution compiles fine with intel 2025 (or even 2024) C++ compiler but doesn't execute properly. It crashes on the line
threads_.push_back(std::thread(&ThreadPool::threadFunc, this, i + 1));
from the "ThreadPool.h" header, triggered by the third line from the Advisor hearder.
Switching the compiler to the latest microsoft's compiler, the solution does compile and execute properly (as everything multi-threaded (or not based) on it).
The project configuration can be seen in the vcxproj file, but I nevertheless put it beneath for sake of conveniance :
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<VCProjectVersion>17.0</VCProjectVersion>
<Keyword>Win32Proj</Keyword>
<ProjectGuid>{7dfba301-3902-46a0-9386-e922834c2279}</ProjectGuid>
<RootNamespace>ConsoleApplication1</RootNamespace>
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v143</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v143</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>Intel C++ Compiler 2025</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>Intel C++ Compiler 2025</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="Shared">
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<LanguageStandard>stdcpplatest</LanguageStandard>
<AdditionalIncludeDirectories>$(MYINTEL_INCLUDE)</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalLibraryDirectories>$(MYINTEL_LIB)</AdditionalLibraryDirectories>
<AdditionalDependencies>mkl_intel_lp64.lib;;mkl_core.lib;mkl_rt.lib;$(CoreLibraryDependencies);%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<LanguageStandard>stdcpplatest</LanguageStandard>
<AdditionalIncludeDirectories>$(MYINTEL_INCLUDE)</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalLibraryDirectories>$(MYINTEL_LIB)</AdditionalLibraryDirectories>
<AdditionalDependencies>mkl_intel_lp64.lib;;mkl_core.lib;mkl_rt.lib;$(CoreLibraryDependencies);%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="ConsoleApplication1.cpp" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="concurrent_queue.h" />
<ClInclude Include="Advisor.h" />
<ClInclude Include="ThreadPool.h" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>
where MYINTEL_INCLUDE and MYINTEL_LIB are system environment variables pointing respectively to C:\Program Files (x86)\Intel\oneAPI\mkl\latest\include and C:\Program Files (x86)\Intel\oneAPI\mkl\latest\lib
What do I do wrong relatively to the intel compiler explaining the crash ?
Link Copied
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Hi, I found that the issue will disappear in release mode or replace the option /MDd with /MD in debug mode, could you confirm if this is a valid workaround on your side ? I also escalated the issue to compiler team, and will get back once there's any updates
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Hi and thank you for your answer. I don't understand what you mean with "I found that the issue will disappear in release mode or replace the option /MDd with /MD in debug mode". You mean in debug mode the issue disappears would the option /MDd be replaced with /MD, correct ? But what do you mean for release mode ?
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Right, I don't see the issue in release mode where /MD is default, could you also verify if this works?
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Hi, Here's another workaround that you can move the global statics to functional local statics as follows, please try to verify on your end.
static ThreadPool* getInstance() { static ThreadPool instance_; return &instance_; }

- Subscribe to RSS Feed
- Mark Topic as New
- Mark Topic as Read
- Float this Topic for Current User
- Bookmark
- Subscribe
- Printer Friendly Page