Skip to content

Shared State#5

Merged
SeverTopan merged 4 commits intosynaptive/masterfrom
synaptive/dev/sever/COM-513_SharedState
Apr 27, 2018
Merged

Shared State#5
SeverTopan merged 4 commits intosynaptive/masterfrom
synaptive/dev/sever/COM-513_SharedState

Conversation

@SeverTopan
Copy link
Copy Markdown

Hayk suggested combining the thread pool's shared state in order to clean up call signatures, and to allow the thread pool to be moved safely.

@SeverTopan SeverTopan self-assigned this Apr 23, 2018
@SeverTopan SeverTopan requested review from doxxx and mmthomas April 23, 2018 20:53
// We now transition into the busy wait state.
task_found = false;
num_busy_waiters.fetch_add(1, std::memory_order_acq_rel);
state->numBusyWaiters().fetch_add(1, std::memory_order_acq_rel);
Copy link
Copy Markdown
Author

@SeverTopan SeverTopan Apr 24, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

would it be useful to cache a reference to the result of numBusyWaiters() so that we don't have to access their values through the reference every time they are called? or is the compiler smart enough to optimize that away?
(same goes for all the other items within the state object)

Copy link
Copy Markdown

@hadamyan hadamyan left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good with a few minor comments.

Comment thread include/thread_pool/thread_pool.hpp Outdated
m_failed_wakeup_retry_cap = rhs.m_failed_wakeup_retry_cap;
m_next_worker = rhs.m_next_worker.load();
m_num_busy_waiters = rhs.m_num_busy_waiters.load();
m_rouser = rhs.m_rouser;
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instead of copy assigning and then setting rhs to nullptr you have to just move it:
m_rouser = std::move(rhs.m_rouser);

This will automatically set the rhs.m_rouser to nullptr

Comment thread include/thread_pool/thread_pool.hpp Outdated
m_num_busy_waiters = rhs.m_num_busy_waiters.load();
m_rouser = rhs.m_rouser;
rhs.m_rouser = nullptr;
m_state = rhs.m_state;
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The same here, just move the smart pointer.

*/
template <typename Task, template<typename> class Queue>
void start(std::vector<std::unique_ptr<Worker<Task, Queue>>>& workers, SlottedBag<Queue>& idle_workers, std::atomic<size_t>& num_busy_waiters);
void start(std::shared_ptr<ThreadPoolState<Task, Queue>> state);
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks much better now.

Comment thread include/thread_pool/thread_pool.hpp Outdated
std::atomic<size_t> m_num_busy_waiters;
std::shared_ptr<Rouser> m_rouser;
std::shared_ptr<ThreadPoolState<Task, Queue>> m_state;
std::atomic<bool> m_moved;
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you don't need an additional flag m_moved because:

  1. Construction/assignment/destruction should be always synchronized and no other member function should be called asynchronously during construction/destruction.
  2. After the move m_state will be null and you can use that to check and throw if a member function is called on a moved thread pool.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍 will use the null check

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can we guarantee atomicity and memory ordering if we rely on the shared pointer being null after move to check whether or not we can make a new post?

Comment thread include/thread_pool/worker.hpp Outdated
throw std::runtime_error("Cannot start Worker: it has previously been started or stopped.");

m_thread = std::thread(&Worker<Task, Queue>::threadFunc, this, id, std::ref(workers), std::ref(idle_workers), std::ref(num_busy_waiters));
m_thread = std::thread(&Worker<Task, Queue>::threadFunc, this, id, std::move(state));
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No matter you use move or not, the outcome is the same here because the function argument "state" shared_ptr has another copy outside. And since you are not moving any ownership here it would be more readable if you just copy without a move. Currently when you read the code it seems that you are passing the ownership of the state object to the newly created thread, which is not the case.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I thought moving the shared pointer saves the copy construction of the instance passed to std::thread, which saves one atomic ref counter increment (and subsequent decrement)?

@SeverTopan
Copy link
Copy Markdown
Author

All review comments addressed!

@SeverTopan SeverTopan merged commit 921e41e into synaptive/master Apr 27, 2018
@SeverTopan SeverTopan deleted the synaptive/dev/sever/COM-513_SharedState branch April 27, 2018 20:33
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants