Skip to content

Commit a023678

Browse files
committed
thread safe factories to avoid initialization data races
1 parent a4f30c6 commit a023678

2 files changed

Lines changed: 103 additions & 12 deletions

File tree

mt-kahypar/partition/factories.h

Lines changed: 11 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,6 @@
2727

2828
#pragma once
2929

30-
#include "kahypar-resources/meta/abstract_factory.h"
31-
3230
#include "mt-kahypar/definitions.h"
3331
#include "mt-kahypar/partition/coarsening/i_coarsener.h"
3432
#include "mt-kahypar/partition/context.h"
@@ -39,32 +37,33 @@
3937
#include "mt-kahypar/partition/refinement/fm/fm_commons.h"
4038
#include "mt-kahypar/partition/refinement/fm/strategies/i_fm_strategy.h"
4139
#include "mt-kahypar/partition/refinement/gains/gain_cache_ptr.h"
40+
#include "mt-kahypar/partition/thread_safe_abstract_factory.h"
4241

4342
namespace mt_kahypar {
4443

4544
typedef struct ip_data_container_s ip_data_container_t;
4645

47-
using CoarsenerFactory = kahypar::meta::Factory<CoarseningAlgorithm,
48-
ICoarsener* (*)(mt_kahypar_hypergraph_t, const Context&, uncoarsening_data_t*)>;
49-
using InitialPartitionerFactory = kahypar::meta::Factory<InitialPartitioningAlgorithm,
46+
using CoarsenerFactory = mt_kahypar::ThreadSafeFactory<CoarseningAlgorithm,
47+
ICoarsener* (*)(mt_kahypar_hypergraph_t, const Context&, uncoarsening_data_t*)>;
48+
using InitialPartitionerFactory = mt_kahypar::ThreadSafeFactory<InitialPartitioningAlgorithm,
5049
IInitialPartitioner* (*)(const InitialPartitioningAlgorithm, ip_data_container_t*, const Context&, const int, const int)>;
5150

52-
using LabelPropagationFactory = kahypar::meta::Factory<LabelPropagationAlgorithm,
51+
using LabelPropagationFactory = mt_kahypar::ThreadSafeFactory<LabelPropagationAlgorithm,
5352
IRefiner* (*)(HypernodeID, HyperedgeID, const Context&, gain_cache_t, IRebalancer&)>;
5453

55-
using JetFactory = kahypar::meta::Factory<JetAlgorithm,
54+
using JetFactory = mt_kahypar::ThreadSafeFactory<JetAlgorithm,
5655
IRefiner* (*)(HypernodeID, HyperedgeID, const Context&, gain_cache_t, IRebalancer&)>;
5756

58-
using FMFactory = kahypar::meta::Factory<FMAlgorithm,
57+
using FMFactory = mt_kahypar::ThreadSafeFactory<FMAlgorithm,
5958
IRefiner* (*)(HypernodeID, HyperedgeID, const Context&, gain_cache_t, IRebalancer&)>;
6059

61-
using FMStrategyFactory = kahypar::meta::Factory<FMAlgorithm, IFMStrategy* (*)(const Context&, FMSharedData&)>;
60+
using FMStrategyFactory = mt_kahypar::ThreadSafeFactory<FMAlgorithm, IFMStrategy* (*)(const Context&, FMSharedData&)>;
6261

63-
using FlowSchedulerFactory = kahypar::meta::Factory<FlowAlgorithm,
62+
using FlowSchedulerFactory = mt_kahypar::ThreadSafeFactory<FlowAlgorithm,
6463
IRefiner* (*)(const HypernodeID, const HyperedgeID, const Context&, gain_cache_t)>;
6564

66-
using RebalancerFactory = kahypar::meta::Factory<RebalancingAlgorithm, IRebalancer* (*)(HypernodeID, const Context&, gain_cache_t)>;
65+
using RebalancerFactory = mt_kahypar::ThreadSafeFactory<RebalancingAlgorithm, IRebalancer* (*)(HypernodeID, const Context&, gain_cache_t)>;
6766

68-
using FlowRefinementFactory = kahypar::meta::Factory<FlowAlgorithm,
67+
using FlowRefinementFactory = mt_kahypar::ThreadSafeFactory<FlowAlgorithm,
6968
IFlowRefiner* (*)(const HyperedgeID, const Context&)>;
7069
} // namespace mt_kahypar
Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
/*******************************************************************************
2+
* MIT License
3+
*
4+
* This file is part of Mt-KaHyPar.
5+
*
6+
* Copyright (C) 2025 Nikolai Maas <nikolai.maas@kit.edu>
7+
*
8+
* Permission is hereby granted, free of charge, to any person obtaining a copy
9+
* of this software and associated documentation files (the "Software"), to deal
10+
* in the Software without restriction, including without limitation the rights
11+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12+
* copies of the Software, and to permit persons to whom the Software is
13+
* furnished to do so, subject to the following conditions:
14+
*
15+
* The above copyright notice and this permission notice shall be included in all
16+
* copies or substantial portions of the Software.
17+
*
18+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24+
* SOFTWARE.
25+
******************************************************************************/
26+
27+
#pragma once
28+
29+
#include <memory>
30+
#include <unordered_map>
31+
#include <mutex>
32+
#include <sstream>
33+
#include <type_traits>
34+
35+
#include "kahypar-resources/meta/function_traits.h"
36+
#include "kahypar-resources/meta/template_parameter_to_string.h"
37+
38+
#include "mt-kahypar/macros.h"
39+
#include "mt-kahypar/utils/exception.h"
40+
41+
42+
namespace mt_kahypar {
43+
template <typename IdentifierType, typename ProductCreator>
44+
class ThreadSafeFactory {
45+
private:
46+
using AbstractProduct = typename std::remove_pointer_t<
47+
typename kahypar::meta::FunctionTraits<ProductCreator>::result_type>;
48+
using AbstractProductPtr = std::unique_ptr<AbstractProduct>;
49+
using UnderlyingIdentifierType = typename std::underlying_type_t<IdentifierType>;
50+
using CallbackMap = std::unordered_map<UnderlyingIdentifierType, ProductCreator>;
51+
52+
public:
53+
ThreadSafeFactory(const ThreadSafeFactory&) = delete;
54+
ThreadSafeFactory(ThreadSafeFactory&&) = delete;
55+
ThreadSafeFactory& operator= (const ThreadSafeFactory&) = delete;
56+
ThreadSafeFactory& operator= (ThreadSafeFactory&&) = delete;
57+
58+
~ThreadSafeFactory() = default;
59+
60+
template <typename I, typename ... ProductParameters>
61+
AbstractProductPtr createObject(const I& id, ProductParameters&& ... params) {
62+
const auto creator = _callbacks.find(static_cast<UnderlyingIdentifierType>(id));
63+
if (creator != _callbacks.end()) {
64+
return AbstractProductPtr((creator->second)(std::forward<ProductParameters>(params) ...));
65+
}
66+
std::stringstream ss;
67+
ss << "Could not load " << kahypar::meta::templateToString<IdentifierType>() << ": " << id << std::endl;
68+
ss << "Please check your .ini config file.";
69+
throw InvalidParameterException(ss.str());
70+
}
71+
72+
static ThreadSafeFactory & getInstance() {
73+
static ThreadSafeFactory _factory_instance;
74+
return _factory_instance;
75+
}
76+
77+
static bool registerObject(const IdentifierType& id, ProductCreator creator) {
78+
static std::mutex lock;
79+
80+
std::lock_guard<std::mutex> guard(lock);
81+
auto& instance = getInstance();
82+
return instance._callbacks.insert({ static_cast<UnderlyingIdentifierType>(id), creator }).second;
83+
}
84+
85+
private:
86+
87+
ThreadSafeFactory() :
88+
_callbacks() { }
89+
90+
CallbackMap _callbacks;
91+
};
92+
} // namespace mtkahypar

0 commit comments

Comments
 (0)