From a84887356487a4fcbd57a90f3ce17914ea8bdd0a Mon Sep 17 00:00:00 2001 From: crupest Date: Tue, 8 Jun 2021 20:22:21 +0800 Subject: import(life): ... --- .../computer-network-experiment/ReadWriteLock.cpp | 59 ++++++++++++++++++++++ 1 file changed, 59 insertions(+) create mode 100644 works/life/computer-network-experiment/ReadWriteLock.cpp (limited to 'works/life/computer-network-experiment/ReadWriteLock.cpp') diff --git a/works/life/computer-network-experiment/ReadWriteLock.cpp b/works/life/computer-network-experiment/ReadWriteLock.cpp new file mode 100644 index 0000000..d9b6e3e --- /dev/null +++ b/works/life/computer-network-experiment/ReadWriteLock.cpp @@ -0,0 +1,59 @@ +#include "ReadWriteLock.h" + +#include +#include + +namespace cru { +ReadWriteLock::ReadWriteLock() { +#ifdef WIN32 + lock_ = std::make_unique(); + InitializeSRWLock(lock_.get()); +#else +#endif +} + +ReadWriteLock::ReadWriteLock(ReadWriteLock &&other) + : lock_(std::move(other.lock_)) {} + +ReadWriteLock &ReadWriteLock::operator=(ReadWriteLock &&other) { + if (this != &other) { + Destroy(); + lock_ = std::move(other.lock_); + } + return *this; +} + +ReadWriteLock::~ReadWriteLock() { Destroy(); } + +void ReadWriteLock::ReadLock() { + assert(lock_); + AcquireSRWLockShared(lock_.get()); +} + +void ReadWriteLock::WriteLock() { + assert(lock_); + AcquireSRWLockExclusive(lock_.get()); +} + +bool ReadWriteLock::ReadTryLock() { + assert(lock_); + return TryAcquireSRWLockShared(lock_.get()) != 0; +} + +bool ReadWriteLock::WriteTryLock() { + assert(lock_); + return TryAcquireSRWLockExclusive(lock_.get()) != 0; +} + +void ReadWriteLock::ReadUnlock() { + assert(lock_); + ReleaseSRWLockShared(lock_.get()); +} + +void ReadWriteLock::WriteUnlock() { + assert(lock_); + ReleaseSRWLockExclusive(lock_.get()); +} + +void ReadWriteLock::Destroy() {} +} // namespace cru \ No newline at end of file -- cgit v1.2.3 From 266d3e262d46225ec08bd5034c26631200442f45 Mon Sep 17 00:00:00 2001 From: crupest Date: Tue, 8 Jun 2021 20:37:49 +0800 Subject: import(life): ... --- .../computer-network-experiment/ReadWriteLock.cpp | 41 +++++++++++++++++++++- .../computer-network-experiment/ReadWriteLock.h | 5 +++ 2 files changed, 45 insertions(+), 1 deletion(-) (limited to 'works/life/computer-network-experiment/ReadWriteLock.cpp') diff --git a/works/life/computer-network-experiment/ReadWriteLock.cpp b/works/life/computer-network-experiment/ReadWriteLock.cpp index d9b6e3e..3509e0b 100644 --- a/works/life/computer-network-experiment/ReadWriteLock.cpp +++ b/works/life/computer-network-experiment/ReadWriteLock.cpp @@ -2,6 +2,7 @@ #include #include +#include namespace cru { ReadWriteLock::ReadWriteLock() { @@ -9,6 +10,8 @@ ReadWriteLock::ReadWriteLock() { lock_ = std::make_unique(); InitializeSRWLock(lock_.get()); #else + lock_.reset(new pthread_rwlock_t(PTHREAD_RWLOCK_INITIALIZER)); + pthread_rwlock_init(lock_.get(), nullptr); #endif } @@ -27,33 +30,69 @@ ReadWriteLock::~ReadWriteLock() { Destroy(); } void ReadWriteLock::ReadLock() { assert(lock_); +#ifdef WIN32 AcquireSRWLockShared(lock_.get()); +#else + pthread_rwlock_rdlock(lock_.get()); +#endif } void ReadWriteLock::WriteLock() { assert(lock_); +#ifdef WIN32 AcquireSRWLockExclusive(lock_.get()); +#else + pthread_rwlock_wrlock(lock_.get()); +#endif } bool ReadWriteLock::ReadTryLock() { assert(lock_); +#ifdef WIN32 return TryAcquireSRWLockShared(lock_.get()) != 0; +#else + return pthread_rwlock_tryrdlock(lock_.get()) == 0; +#endif } bool ReadWriteLock::WriteTryLock() { assert(lock_); +#ifdef WIN32 return TryAcquireSRWLockExclusive(lock_.get()) != 0; +#else + return pthread_rwlock_trywrlock(lock_.get()) == 0; +#endif } void ReadWriteLock::ReadUnlock() { assert(lock_); +#ifdef WIN32 ReleaseSRWLockShared(lock_.get()); +#else + pthread_rwlock_unlock(lock_.get()); +#endif } void ReadWriteLock::WriteUnlock() { assert(lock_); +#ifdef WIN32 ReleaseSRWLockExclusive(lock_.get()); +#else + pthread_rwlock_unlock(lock_.get()); +#endif +} + +void ReadWriteLock::Destroy() { +#ifndef WIN32 + if (lock_ != nullptr) + pthread_rwlock_destroy(lock_.get()); +#endif +} + +void swap(ReadWriteLock &left, ReadWriteLock &right) { + auto temp = std::move(left.lock_); + left.lock_ = std::move(right.lock_); + right.lock_ = std::move(temp); } -void ReadWriteLock::Destroy() {} } // namespace cru \ No newline at end of file diff --git a/works/life/computer-network-experiment/ReadWriteLock.h b/works/life/computer-network-experiment/ReadWriteLock.h index c9889da..ee40ac0 100644 --- a/works/life/computer-network-experiment/ReadWriteLock.h +++ b/works/life/computer-network-experiment/ReadWriteLock.h @@ -6,10 +6,12 @@ #ifdef WIN32 #include #else +#include #endif namespace cru { class ReadWriteLock { + friend void swap(ReadWriteLock &left, ReadWriteLock &right); public: ReadWriteLock(); @@ -35,6 +37,9 @@ private: #ifdef WIN32 std::unique_ptr lock_; #else + std::unique_ptr lock_; #endif }; + +void swap(ReadWriteLock &left, ReadWriteLock &right); } // namespace cru -- cgit v1.2.3 From 33ece81cf15b3cb8d4a005194acc67c3a3e5ad35 Mon Sep 17 00:00:00 2001 From: crupest Date: Tue, 8 Jun 2021 20:50:30 +0800 Subject: import(life): ... --- .../computer-network-experiment/ReadWriteLock.cpp | 1 - works/life/computer-network-experiment/TODO.md | 6 +++-- works/life/computer-network-experiment/server.cpp | 26 +++++++++++++++++++++- 3 files changed, 29 insertions(+), 4 deletions(-) (limited to 'works/life/computer-network-experiment/ReadWriteLock.cpp') diff --git a/works/life/computer-network-experiment/ReadWriteLock.cpp b/works/life/computer-network-experiment/ReadWriteLock.cpp index 3509e0b..46d2857 100644 --- a/works/life/computer-network-experiment/ReadWriteLock.cpp +++ b/works/life/computer-network-experiment/ReadWriteLock.cpp @@ -2,7 +2,6 @@ #include #include -#include namespace cru { ReadWriteLock::ReadWriteLock() { diff --git a/works/life/computer-network-experiment/TODO.md b/works/life/computer-network-experiment/TODO.md index 77bf0fc..248a2d7 100644 --- a/works/life/computer-network-experiment/TODO.md +++ b/works/life/computer-network-experiment/TODO.md @@ -1,4 +1,6 @@ -1. Apply read-write lock to connections. -2. Remove dead connection from connection list. +1. Apply read-write lock to connections. ✅ +2. Remove dead connection from connection list. ✅ 3. Handle SIGINT gracefully. 4. Add close method to protocol. +5. Add help and exit command. +6. Use multiprocess to show output. diff --git a/works/life/computer-network-experiment/server.cpp b/works/life/computer-network-experiment/server.cpp index 03d27ad..065687c 100644 --- a/works/life/computer-network-experiment/server.cpp +++ b/works/life/computer-network-experiment/server.cpp @@ -4,6 +4,7 @@ #include "Common.h" #include "IO.h" +#include "ReadWriteLock.h" #include #include @@ -26,12 +27,14 @@ const auto bind_address = "127.0.0.1"; // control bind address const u_short port = 1234; // control bind port +namespace { void PrintHelp() { SendOutput(CRUT( "Input and run one of following command:\n\t> NOTHING -> Continue and " "print new messages.\n\t> list -> List all connected client.\n\t> send " "[i] [message] -> Send messages to client with number i.\n")); } +} // namespace struct Connection { int id; @@ -45,9 +48,24 @@ struct Connection { folly::CancellationSource cancellation_source; }; +namespace { +cru::ReadWriteLock connections_lock; std::vector> connections; +void RemoveConnection(int id) { + connections_lock.WriteLock(); + connections.erase( + std::remove_if(connections.begin(), connections.end(), + [id](const std::unique_ptr &connection) { + return connection->id == id; + }), + connections.end()); + + connections_lock.WriteUnlock(); +} + void PrintConnections() { + connections_lock.ReadLock(); if (connections.empty()) { SendOutput(CRUT("Currently there is no connection.\n")); } @@ -58,7 +76,9 @@ void PrintConnections() { connection->address_string); } SendOutput(s); + connections_lock.ReadUnlock(); } +} // namespace void ResponseThreadProc(Connection *connection) { auto host = ConvertCharString(inet_ntoa(connection->address.sin_addr)); @@ -120,6 +140,8 @@ void ResponseThreadProc(Connection *connection) { } CloseSocket(connection->socket); + + RemoveConnection(connection->id); } void OnInputLine(StringView line) { @@ -164,7 +186,7 @@ void OnInputLine(StringView line) { [id](const std::unique_ptr &c) { return c->id == id; }); if (i == connections.end()) { - SendOutput(OutputType::Error, CRUT("No connection with such id.!\n")); + SendOutput(OutputType::Error, CRUT("No connection with such id.\n")); return; } @@ -224,6 +246,7 @@ int Main() { PrintErrorMessageAndExit(CRUT("Failed to accecpt.")); } + connections_lock.WriteLock(); connections.push_back(std::make_unique()); const std::unique_ptr &connection = connections.back(); @@ -233,5 +256,6 @@ int Main() { connection->thread = std::thread(ResponseThreadProc, connections.back().get()); connection->thread.detach(); + connections_lock.WriteUnlock(); } } -- cgit v1.2.3