iterative-solver 0.0
util.h
1#ifndef LINEARALGEBRA_SRC_MOLPRO_LINALG_ARRAY_UTIL_H
2#define LINEARALGEBRA_SRC_MOLPRO_LINALG_ARRAY_UTIL_H
3#include <atomic>
4#include <future>
5#include <memory>
6#include <string>
7#include <vector>
8
9#include <molpro/mpi.h>
10
12
14class LockMPI3 {
15protected:
16 MPI_Comm m_comm = MPI_COMM_NULL;
17 MPI_Win m_win = MPI_WIN_NULL;
18 bool m_locked = false;
19
20public:
22 LockMPI3(MPI_Comm comm);
24 ~LockMPI3();
25
26 LockMPI3() = delete;
27 LockMPI3(const LockMPI3 &) = delete;
28 LockMPI3 &operator=(const LockMPI3 &) = delete;
29
31 void lock();
32
34 void unlock();
35
36protected:
38 struct Proxy {
40 explicit Proxy(LockMPI3 &);
41 Proxy() = delete;
42 ~Proxy();
43
44 bool m_deleted = false;
45 };
46
48 std::weak_ptr<Proxy> m_proxy;
49
50public:
53 std::shared_ptr<Proxy> scope();
54};
55
57class ScopeLock {
58public:
59 explicit ScopeLock(MPI_Comm comm) : lock{comm}, l{lock.scope()} {}
60
61protected:
63 decltype(std::declval<LockMPI3>().scope()) l;
64};
65
66template <typename Result = void>
67class Task {
68public:
69 Task(std::future<Result> &&task) : m_task{std::move(task)} {};
70 Task(Task &&other) = default;
71
72 template <class Func, typename... Args>
73 static Task create(Func &&f, Args &&...args) {
74 return {std::async(std::launch::async, std::forward<Func>(f), std::forward<Args>(args)...)};
75 }
76
77 ~Task() { wait(); }
78
80 bool test() { return m_task.wait_for(std::chrono::microseconds{1}) == std::future_status::ready; }
82 Result wait() {
83 if (!m_task.valid())
84 throw std::future_error(std::future_errc::no_state);
85 return m_task.get();
86 }
87
88protected:
89 std::future<Result> m_task;
90};
91
92} // namespace molpro::linalg::array::util
93
94#endif // LINEARALGEBRA_SRC_MOLPRO_LINALG_ARRAY_UTIL_H
Atomic lock allowing only one process to acquire it. Implemented using MPI3 RMA.
Definition: util.h:14
void unlock()
Release the lock.
Definition: util.cpp:24
MPI_Comm m_comm
MPI communicator.
Definition: util.h:16
~LockMPI3()
Release the lock and destroy it. This is collective and must be called by all processes in the commun...
Definition: util.cpp:10
void lock()
Acquire exclusive lock.
Definition: util.cpp:17
std::shared_ptr< Proxy > scope()
Definition: util.cpp:31
bool m_locked
whether lock is active
Definition: util.h:18
std::weak_ptr< Proxy > m_proxy
Keep track of proxy object so that if lock is deleted, the proxy does not try to unlock.
Definition: util.h:48
LockMPI3(const LockMPI3 &)=delete
LockMPI3 & operator=(const LockMPI3 &)=delete
MPI_Win m_win
empty window handle
Definition: util.h:17
Utility object that locks on creation and unlocks on destruction.
Definition: util.h:57
LockMPI3 lock
Definition: util.h:62
ScopeLock(MPI_Comm comm)
Definition: util.h:59
decltype(std::declval< LockMPI3 >().scope()) l
Definition: util.h:63
Task(Task &&other)=default
static Task create(Func &&f, Args &&...args)
Definition: util.h:73
Task(std::future< Result > &&task)
Definition: util.h:69
Result wait()
wait for the task to complete and return its result
Definition: util.h:82
std::future< Result > m_task
Definition: util.h:89
~Task()
Definition: util.h:77
bool test()
Returns true if the task has completed.
Definition: util.h:80
Definition: ArrayHandler.h:23
Proxy that locks on creation and unlocks on destruction. Useful for locking a scope.
Definition: util.h:38
LockMPI3 & m_lock
Definition: util.h:39
bool m_deleted
whether the lock was already deleted
Definition: util.h:44