Originally I had thought about designing a ThreadManager
class to store threads
along with the data type objects
and function type objects
that they would work with. The class was to be responsible for the managing of memory, access, transferring, releasing, locking, unlocking, joining, and other typical common functionalities of the associated types within the standard multithreading library. It was originally intended to associate the containing thread and its id with a specific set of resources that a particular thread has access to.
After reading through the docs on cppreference
about mutex
, shared_mutex
, lock_guard
, shared_lock
, std::function<...>
, etc. and now knowing that mutexes
and lock_guards
are non copyable and the fact that if I template the class to store arbitrary function objects
, function pointers
, lambdas
or std::function<>
s as a std::function<>
within this class's container that the class instantiation of this intended singleton would only be able to store a specific function signature limiting it to not be able to instantiate any other declaration signature.
Concerning these behaviors and properties of the multithreading library within the standard library for mutexes
, shared_mutexes
lock_guards
, threads
, promises
, futures
etc... it came to mind that I'm overthinking the overall design of this class.
You can refer to my initial design attempt via this previously asked question of mine. Storing arbitrary function objects into a class member container without knowing their declaration signature, This should give you an idea of what I was attempting to do.
Understanding a little more about their behaviors, properties and responsibilities I would like to know if the following would be appropriate for the intended design process.
Instead of storing any mutexes
, lock_guards
, threads
, data type objects
or function objects
; would it make more sense to just store the generated ids
of the threads
, and have my manager class act more like a monitoring, recording, and reporting type class instead?
My new intentions would be that the container would store the thread's ID in an associated map as its key along with an associated common struct. The struct would contain a property list of all the responsibilities and actions of the combined resources. This may then allow support for some of the following features: a priority queue, a task scheduler, a dispatcher of commands to send and fetch resources knowing if the thread is available or not, where these types of actions will not be done by this class directly but through generic function templates.
For example:
struct ThreadProperties {
// thread specific
id,
slept for,
is locked,
is waiting,
is joined,
has mutex, if so hold id to mutex - lockguard
is shared,
is active,
has promise or future...
who has ownership of,
marked for release,
marked for transfer
// other mutex and lock_guard properties
// function object address stored as `size_t` to represent an id
// data object address stored as `size_t` to represent an id
// etc.
};
class ThreadManager {
private:
std::map<unsigned, ThreadProperites> threadTable;
public:
default constructor
storeIds into relevant containers
store properties into relevant containers
associate above containers into a map or lookup table
find or look for specific ID and if found
check to see its current status and report it
also check to see if it's in a priority queue
or task scheduler and determine if it is ready
to do something, or change its internal state.
other common methods of functionality associated with threads.
};
// function templates to act on threads according to the reporting of the manager above.
With my intention to implement this kind of design while trying to maintain the best practices of modern c++ targeting c++17; would this kind of design be appropriate for proper class design to be generic, modular, portable and efficient for use?