public inbox for libstdc++@gcc.gnu.org
 help / color / mirror / Atom feed
From: "Alessio G. B." <alessiogiovanni.baroni@gmail.com>
To: libstdc++@gcc.gnu.org
Subject: [PATCH] libstdc++: Implementation of class strand
Date: Fri, 12 Mar 2021 13:21:47 +0100	[thread overview]
Message-ID: <CANDuHT+S6jZyOohT9f+hhSOkj=0K9vnVhQUK5oV2HhFg2D=t5g@mail.gmail.com> (raw)

[-- Attachment #1: Type: text/plain, Size: 430 bytes --]

I expanded the implementation of the class strand of the Networking
TS. Essentially, I
implemented a token system so each thread knows when it can execute;
the system is organized
with 2 integers moving as a clock.

2021-03-12 Alessio G. Baroni <alessiogiovanni.baroni@gmail.com>

        libstdc++-v3:
            * include/experimental/executor: Implemented algorithm for
serial execution regardless of the underlying Executor.

[-- Attachment #2: strand.patch --]
[-- Type: text/x-patch, Size: 4684 bytes --]

diff --git a/libstdc++-v3/include/experimental/executor b/libstdc++-v3/include/experimental/executor
index c670f2739b6..afd5a64366f 100644
--- a/libstdc++-v3/include/experimental/executor
+++ b/libstdc++-v3/include/experimental/executor
@@ -1478,13 +1478,16 @@ inline namespace v1
 
       // construct / copy / destroy:
 
-      strand(); // TODO make state
+      strand() : _M_state(std::make_shared<_State>()) { }
 
-      explicit strand(_Executor __ex) : _M_inner_ex(__ex) { } // TODO make state
+      explicit strand(_Executor __ex)
+	  : _M_state(std::make_shared<_State>()),
+	    _M_inner_ex(__ex) { }
 
       template<typename _Alloc>
 	strand(allocator_arg_t, const _Alloc& __a, _Executor __ex)
-	: _M_inner_ex(__ex) { } // TODO make state
+	: _M_state(std::allocate_shared<_State>(__a)),
+	  _M_inner_ex(__ex) { }
 
       strand(const strand& __other) noexcept
       : _M_state(__other._M_state), _M_inner_ex(__other._M_inner_ex) { }
@@ -1508,8 +1511,10 @@ inline namespace v1
 	static_assert(is_copy_assignable<_Executor>::value,
 		      "inner executor type must be CopyAssignable");
 
-	// TODO lock __other
-	// TODO copy state
+#if defined(_GLIBCXX_HAS_GTHREADS)
+	std::lock_guard<std::mutex> __lock(__other._M_state->_M_mutex);
+#endif
+	_M_state = __other._M_state;
 	_M_inner_ex = __other._M_inner_ex;
 	return *this;
       }
@@ -1520,7 +1525,10 @@ inline namespace v1
 	static_assert(is_move_assignable<_Executor>::value,
 		      "inner executor type must be MoveAssignable");
 
-	// TODO move state
+#if defined(_GLIBCXX_HAS_GTHREADS)
+	std::lock_guard<std::mutex> __lock(__other._M_state->_M_mutex);
+#endif
+	_M_state = std::move(__other._M_state);
 	_M_inner_ex = std::move(__other._M_inner_ex);
 	return *this;
       }
@@ -1532,8 +1540,10 @@ inline namespace v1
 	  static_assert(is_convertible<_OtherExecutor, _Executor>::value,
 			"inner executor type must be compatible");
 
-	  // TODO lock __other
-	  // TODO copy state
+#if defined(_GLIBCXX_HAS_GTHREADS)
+	  std::lock_guard<std::mutex> __lock(__other._M_state->_M_mutex);
+#endif
+	  _M_state = __other._M_state;
 	  _M_inner_ex = __other._M_inner_ex;
 	  return *this;
 	}
@@ -1545,15 +1555,16 @@ inline namespace v1
 	  static_assert(is_convertible<_OtherExecutor, _Executor>::value,
 			"inner executor type must be compatible");
 
-	  // TODO move state
+#if defined(_GLIBCXX_HAS_GTHREADS)
+	  std::lock_guard<std::mutex> __lock(__other._M_state->_M_mutex);
+#endif
+	  _M_state = std::move(__other._M_state);
 	  _M_inner_ex = std::move(__other._M_inner_ex);
 	  return *this;
 	}
 
       ~strand()
       {
-	// the task queue outlives this object if non-empty
-	// TODO create circular ref in queue?
       }
 
       // strand operations:
@@ -1585,7 +1596,21 @@ inline namespace v1
 
       template<typename _Func, typename _Alloc>
 	void
-	post(_Func&& __f, const _Alloc& __a) const; // TODO
+	post(_Func&& __f, const _Alloc& __a) const
+        {
+#if defined(_GLIBCXX_HAS_GTHREADS)
+	  auto token = _M_state->new_token();
+
+	  _M_inner_ex.post(
+	      [token, __state = _M_state, &__f]()
+	      {
+		__state->invoke(token, std::forward<_Func>(__f));
+	      },
+	      __a);
+#else
+	  _M_inner_ex.post(std::forward<_Func>(__f), __a);
+#endif
+	}
 
       template<typename _Func, typename _Alloc>
 	void
@@ -1597,19 +1622,56 @@ inline namespace v1
       operator==(const strand& __a, const strand& __b)
       { return __a._M_state == __b._M_state; }
 
-      // TODO add synchronised queue
       struct _State
       {
 #if defined(_GLIBCXX_HAS_GTHREADS)
+	_State()
+	    : _M_running_on(std::this_thread::get_id()),
+	      _M_next_token(0),
+	      _M_last_token(0) { }
+
 	bool
 	running_in_this_thread() const noexcept
 	{ return std::this_thread::get_id() == _M_running_on; }
 
+	unsigned int
+	new_token()
+	{
+	  std::lock_guard<std::mutex> __lock(_M_mutex);
+
+	  return _M_last_token++;
+	}
+
+	template<typename _Func>
+	void
+	invoke(unsigned int token, _Func&& __f)
+	{
+	  std::unique_lock<std::mutex> __lock(_M_mutex);
+
+	  _M_cv.wait(__lock,
+		     [token, next_token = _M_next_token]()
+		     { return token == next_token; });
+
+	  try { decay_t<_Func>{std::forward<_Func>(__f)}(); }
+	  catch(...) { }
+
+	  _M_next_token++;
+
+	  __lock.unlock();
+
+	  _M_cv.notify_all();
+	}
+
 	std::thread::id _M_running_on;
+	std::mutex _M_mutex;
+	std::condition_variable _M_cv;
+	unsigned int _M_next_token;
+	unsigned int _M_last_token;
 #else
-	bool running_in_this_thread() const { return true; }
+	bool running_in_this_thread() const noexcept { return true; }
 #endif
       };
+
       shared_ptr<_State> _M_state;
       _Executor _M_inner_ex;
     };

             reply	other threads:[~2021-03-12 12:22 UTC|newest]

Thread overview: 4+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2021-03-12 12:21 Alessio G. B. [this message]
2021-03-23 16:39 ` Jonathan Wakely
2023-03-22 14:31   ` Jonathan Wakely
2023-04-10 19:42     ` Thomas Rodgers

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to='CANDuHT+S6jZyOohT9f+hhSOkj=0K9vnVhQUK5oV2HhFg2D=t5g@mail.gmail.com' \
    --to=alessiogiovanni.baroni@gmail.com \
    --cc=libstdc++@gcc.gnu.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).