feature add Mutex,ConditionVariable,Event,MutexGuard
Some checks failed
rpcrypto-build / build (Debug, hisiv510.toolchain.cmake) (push) Successful in 52s
linux-x64-gcc / linux-gcc (push) Failing after 56s
linux-mips64-gcc / linux-gcc-mips64el (push) Failing after 57s
rpcrypto-build / build (Debug, himix200.toolchain.cmake) (push) Successful in 1m18s
rpcrypto-build / build (Debug, mipsel-openwrt-linux-musl.toolchain.cmake) (push) Failing after 1m17s
rpcrypto-build / build (Release, mipsel-openwrt-linux.toolchain.cmake) (push) Failing after 1m15s
rpcrypto-build / build (Release, himix200.toolchain.cmake) (push) Successful in 1m25s
linux-hisiv500-gcc / linux-gcc-hisiv500 (push) Successful in 1m23s
rpcrypto-build / build (Release, hisiv510.toolchain.cmake) (push) Successful in 1m29s
rpcrypto-build / build (Debug, mipsel-openwrt-linux.toolchain.cmake) (push) Failing after 1m3s
rpcrypto-build / build (Release, mipsel-openwrt-linux-musl.toolchain.cmake) (push) Failing after 1m21s
Some checks failed
rpcrypto-build / build (Debug, hisiv510.toolchain.cmake) (push) Successful in 52s
linux-x64-gcc / linux-gcc (push) Failing after 56s
linux-mips64-gcc / linux-gcc-mips64el (push) Failing after 57s
rpcrypto-build / build (Debug, himix200.toolchain.cmake) (push) Successful in 1m18s
rpcrypto-build / build (Debug, mipsel-openwrt-linux-musl.toolchain.cmake) (push) Failing after 1m17s
rpcrypto-build / build (Release, mipsel-openwrt-linux.toolchain.cmake) (push) Failing after 1m15s
rpcrypto-build / build (Release, himix200.toolchain.cmake) (push) Successful in 1m25s
linux-hisiv500-gcc / linux-gcc-hisiv500 (push) Successful in 1m23s
rpcrypto-build / build (Release, hisiv510.toolchain.cmake) (push) Successful in 1m29s
rpcrypto-build / build (Debug, mipsel-openwrt-linux.toolchain.cmake) (push) Failing after 1m3s
rpcrypto-build / build (Release, mipsel-openwrt-linux-musl.toolchain.cmake) (push) Failing after 1m21s
This commit is contained in:
parent
2a8b1d873e
commit
91e96b17b2
@ -2,18 +2,18 @@ name: linux-x64-gcc
|
||||
on:
|
||||
push:
|
||||
paths:
|
||||
- '.gitea/workflows/linux-x64-gcc.yml'
|
||||
- 'src/**'
|
||||
- 'tests/**'
|
||||
- 'CMakeLists.txt'
|
||||
- 'cmake/**'
|
||||
- ".gitea/workflows/linux-x64-gcc.yml"
|
||||
- "src/**"
|
||||
- "tests/**"
|
||||
- "CMakeLists.txt"
|
||||
- "cmake/**"
|
||||
pull_request:
|
||||
paths:
|
||||
- '.gitea/workflows/linux-x64-gcc.yml'
|
||||
- 'src/**'
|
||||
- 'tests/**'
|
||||
- 'CMakeLists.txt'
|
||||
- 'cmake/**'
|
||||
- ".gitea/workflows/linux-x64-gcc.yml"
|
||||
- "src/**"
|
||||
- "tests/**"
|
||||
- "CMakeLists.txt"
|
||||
- "cmake/**"
|
||||
concurrency:
|
||||
group: linux-x64-gcc-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
@ -50,4 +50,5 @@ jobs:
|
||||
cmake --build build-shared -j `nproc`
|
||||
- name: test-shared
|
||||
run: |
|
||||
cd build-shared && ctest --output-on-failure -j `nproc`
|
||||
cd build-shared && ctest --output-on-failure -j `nproc`
|
||||
|
||||
|
@ -8,11 +8,21 @@ set(CMAKE_CXX_EXTENSIONS OFF)
|
||||
option(ULIB_BUILD_TESTS "Build tests" OFF)
|
||||
option(ULIB_SHARED_LIB "Build shared library" OFF)
|
||||
|
||||
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
|
||||
if (ULIB_SHARED_LIB)
|
||||
add_library(${PROJECT_NAME} SHARED "")
|
||||
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
|
||||
else()
|
||||
add_library(${PROJECT_NAME} STATIC "")
|
||||
add_library(${PROJECT_NAME} STATIC ""
|
||||
src/ulib/concorrency/mutex.cpp
|
||||
src/ulib/concorrency/mutex.h
|
||||
src/ulib/concorrency/condition_variable.cpp
|
||||
src/ulib/concorrency/condition_variable.h
|
||||
src/ulib/concorrency/internal/mutex_impl.cpp
|
||||
src/ulib/concorrency/internal/mutex_impl.h
|
||||
src/ulib/concorrency/internal/condition_variable_impl.cpp
|
||||
src/ulib/concorrency/internal/condition_variable_impl.h
|
||||
src/ulib/concorrency/event.cpp
|
||||
src/ulib/concorrency/event.h)
|
||||
endif()
|
||||
|
||||
find_package(Threads REQUIRED)
|
||||
@ -31,7 +41,6 @@ set(FMT_TEST OFF CACHE BOOL "Build tests" FORCE)
|
||||
set(FMT_USE_CPP11 OFF CACHE BOOL "Use C++11" FORCE)
|
||||
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/3party/fmt)
|
||||
|
||||
|
||||
target_sources(${PROJECT_NAME} PRIVATE
|
||||
src/ulib/empty.cpp
|
||||
src/ulib/log/logger.cpp
|
||||
|
38
src/ulib/concorrency/condition_variable.cpp
Normal file
38
src/ulib/concorrency/condition_variable.cpp
Normal file
@ -0,0 +1,38 @@
|
||||
//
|
||||
// Created by Feng Zhang on 2023/12/12.
|
||||
//
|
||||
|
||||
#include "condition_variable.h"
|
||||
#include "internal/condition_variable_impl.h"
|
||||
|
||||
namespace ulib {
|
||||
|
||||
ConditionVariable::ConditionVariable() : impl_(new detail::ConditionVariableImpl) {}
|
||||
|
||||
ConditionVariable::~ConditionVariable() { delete impl_; }
|
||||
|
||||
void
|
||||
ConditionVariable::NotifyOne()
|
||||
{
|
||||
impl_->NotifyOne();
|
||||
}
|
||||
|
||||
void
|
||||
ConditionVariable::NotifyAll()
|
||||
{
|
||||
impl_->NotifyAll();
|
||||
}
|
||||
|
||||
void
|
||||
ConditionVariable::Wait(MutexGuard &guard)
|
||||
{
|
||||
impl_->Wait(*guard.mutex_.impl_);
|
||||
}
|
||||
|
||||
bool
|
||||
ConditionVariable::WaitForMilliseconds(MutexGuard &guard, uint32_t wait_time)
|
||||
{
|
||||
return impl_->WaitForMilliseconds(*guard.mutex_.impl_, wait_time);
|
||||
}
|
||||
|
||||
}
|
47
src/ulib/concorrency/condition_variable.h
Normal file
47
src/ulib/concorrency/condition_variable.h
Normal file
@ -0,0 +1,47 @@
|
||||
//
|
||||
// Created by Feng Zhang on 2023/12/12.
|
||||
//
|
||||
|
||||
#ifndef ULIB_SRC_ULIB_CONCORRENCY_CONDITION_VARIABLE_H_
|
||||
#define ULIB_SRC_ULIB_CONCORRENCY_CONDITION_VARIABLE_H_
|
||||
|
||||
#include "mutex.h"
|
||||
#include "ulib/base/types.h"
|
||||
|
||||
namespace ulib {
|
||||
|
||||
namespace detail {
|
||||
class ConditionVariableImpl;
|
||||
}
|
||||
|
||||
class ConditionVariable {
|
||||
public:
|
||||
ConditionVariable();
|
||||
~ConditionVariable();
|
||||
|
||||
void NotifyOne();
|
||||
void NotifyAll();
|
||||
|
||||
void Wait(MutexGuard &guard);
|
||||
bool WaitForMilliseconds(MutexGuard &guard, uint32_t wait_time);
|
||||
|
||||
template<class Predicate>
|
||||
void Wait(MutexGuard &guard, Predicate p)
|
||||
{
|
||||
while (!p()) { Wait(guard); }
|
||||
}
|
||||
|
||||
template<class Predicate>
|
||||
bool WaitForMilliseconds(MutexGuard &guard, uint32_t wait_time, Predicate p)
|
||||
{
|
||||
if (!p()) { WaitForMilliseconds(guard, wait_time); }
|
||||
return p();
|
||||
}
|
||||
|
||||
private:
|
||||
detail::ConditionVariableImpl *impl_;
|
||||
};
|
||||
|
||||
}// namespace ulib
|
||||
|
||||
#endif//ULIB_SRC_ULIB_CONCORRENCY_CONDITION_VARIABLE_H_
|
64
src/ulib/concorrency/event.cpp
Normal file
64
src/ulib/concorrency/event.cpp
Normal file
@ -0,0 +1,64 @@
|
||||
//
|
||||
// Created by Feng Zhang on 2023/12/13.
|
||||
//
|
||||
|
||||
#include "event.h"
|
||||
|
||||
ulib::Event::Event() : manual_reset_(false), event_status_(false) {}
|
||||
|
||||
ulib::Event::Event(bool manual_reset, bool initially_signaled)
|
||||
: manual_reset_(manual_reset),
|
||||
event_status_(initially_signaled)
|
||||
{}
|
||||
|
||||
ulib::Event::~Event() {}
|
||||
|
||||
void
|
||||
ulib::Event::Set()
|
||||
{
|
||||
MutexGuard guard(mutex_);
|
||||
event_status_ = true;
|
||||
cond_.NotifyAll();
|
||||
}
|
||||
|
||||
void
|
||||
ulib::Event::Reset()
|
||||
{
|
||||
MutexGuard guard(mutex_);
|
||||
event_status_ = false;
|
||||
}
|
||||
|
||||
bool
|
||||
ulib::Event::Wait(int give_up_after_ms)
|
||||
{
|
||||
MutexGuard guard(mutex_);
|
||||
if (event_status_) { return true; }
|
||||
|
||||
IsEventSetChecker checker(*this);
|
||||
if (give_up_after_ms <= 0) {
|
||||
cond_.Wait(guard, checker);
|
||||
} else {
|
||||
cond_.WaitForMilliseconds(guard, give_up_after_ms, checker);
|
||||
}
|
||||
|
||||
if (event_status_) {
|
||||
if (manual_reset_) { event_status_ = false; }
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
ulib::Event::operator()() const
|
||||
{
|
||||
return event_status_;
|
||||
}
|
||||
|
||||
ulib::Event::IsEventSetChecker::IsEventSetChecker(const ulib::Event &event) : event_(event) {}
|
||||
|
||||
bool
|
||||
ulib::Event::IsEventSetChecker::operator()()
|
||||
{
|
||||
return event_.event_status_;
|
||||
}
|
50
src/ulib/concorrency/event.h
Normal file
50
src/ulib/concorrency/event.h
Normal file
@ -0,0 +1,50 @@
|
||||
//
|
||||
// Created by Feng Zhang on 2023/12/13.
|
||||
//
|
||||
|
||||
#ifndef ULIB_SRC_ULIB_CONCORRENCY_EVENT_H_
|
||||
#define ULIB_SRC_ULIB_CONCORRENCY_EVENT_H_
|
||||
|
||||
#include "mutex.h"
|
||||
#include "condition_variable.h"
|
||||
|
||||
namespace ulib {
|
||||
class Event {
|
||||
public:
|
||||
Event();
|
||||
Event(bool manual_reset, bool initially_signaled);
|
||||
~Event();
|
||||
|
||||
void Set();
|
||||
void Reset();
|
||||
/**
|
||||
* @brief
|
||||
* @param give_up_after_ms -1, always wait, > 0 set timeout
|
||||
* @return
|
||||
*/
|
||||
bool Wait(int give_up_after_ms = -1);
|
||||
bool operator()() const;
|
||||
|
||||
private:
|
||||
class IsEventSetChecker {
|
||||
public:
|
||||
IsEventSetChecker(const Event &);
|
||||
bool operator()();
|
||||
|
||||
private:
|
||||
const Event &event_;
|
||||
};
|
||||
|
||||
Event(const Event &);
|
||||
Event &operator=(const Event &);
|
||||
|
||||
const bool manual_reset_;
|
||||
Mutex mutex_;
|
||||
ConditionVariable cond_;
|
||||
bool event_status_;
|
||||
|
||||
friend class IsEventSetChecker;
|
||||
};
|
||||
}// namespace ulib
|
||||
|
||||
#endif//ULIB_SRC_ULIB_CONCORRENCY_EVENT_H_
|
@ -0,0 +1,5 @@
|
||||
//
|
||||
// Created by Feng Zhang on 2023/12/12.
|
||||
//
|
||||
|
||||
#include "condition_variable_impl.h"
|
58
src/ulib/concorrency/internal/condition_variable_impl.h
Normal file
58
src/ulib/concorrency/internal/condition_variable_impl.h
Normal file
@ -0,0 +1,58 @@
|
||||
//
|
||||
// Created by Feng Zhang on 2023/12/12.
|
||||
//
|
||||
|
||||
#ifndef ULIB_SRC_ULIB_CONCORRENCY_INTERNAL_CONDITION_VARIABLE_IMPL_H_
|
||||
#define ULIB_SRC_ULIB_CONCORRENCY_INTERNAL_CONDITION_VARIABLE_IMPL_H_
|
||||
|
||||
#include "ulib/base/types.h"
|
||||
#include "mutex_impl.h"
|
||||
#include "ulib/concorrency/mutex.h"
|
||||
#include <algorithm>
|
||||
#include <pthread.h>
|
||||
#include <errno.h>
|
||||
|
||||
namespace ulib {
|
||||
namespace detail {
|
||||
|
||||
class ConditionVariableImpl {
|
||||
public:
|
||||
ConditionVariableImpl() { pthread_cond_init(&cond_, NULL); }
|
||||
|
||||
~ConditionVariableImpl() { pthread_cond_destroy(&cond_); }
|
||||
|
||||
void NotifyOne() { pthread_cond_signal(&cond_); }
|
||||
|
||||
void NotifyAll() { pthread_cond_broadcast(&cond_); }
|
||||
|
||||
void Wait(MutexImpl &mutex_impl) { pthread_cond_wait(&cond_, &mutex_impl.mutex_); }
|
||||
|
||||
template<class Predicate>
|
||||
void Wait(MutexImpl &mutex_impl, Predicate p)
|
||||
{
|
||||
while (!p()) { Wait(mutex_impl); }
|
||||
}
|
||||
|
||||
bool WaitForMilliseconds(MutexImpl &mutex_impl, uint32_t wait_time)
|
||||
{
|
||||
struct timespec ts;
|
||||
ts.tv_sec = 0;
|
||||
ts.tv_nsec = wait_time * 1000000;
|
||||
return ETIMEDOUT != pthread_cond_timedwait(&cond_, &mutex_impl.mutex_, &ts);
|
||||
}
|
||||
|
||||
template<class Predicate>
|
||||
bool WaitForMilliseconds(MutexImpl &mutex_impl, uint32_t wait_time, Predicate p)
|
||||
{
|
||||
if (!p()) { WaitForMilliseconds(mutex_impl, wait_time); }
|
||||
return p();
|
||||
}
|
||||
|
||||
private:
|
||||
pthread_cond_t cond_;
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
}// namespace ulib
|
||||
|
||||
#endif//ULIB_SRC_ULIB_CONCORRENCY_INTERNAL_CONDITION_VARIABLE_IMPL_H_
|
5
src/ulib/concorrency/internal/mutex_impl.cpp
Normal file
5
src/ulib/concorrency/internal/mutex_impl.cpp
Normal file
@ -0,0 +1,5 @@
|
||||
//
|
||||
// Created by Feng Zhang on 2023/12/12.
|
||||
//
|
||||
|
||||
#include "mutex_impl.h"
|
31
src/ulib/concorrency/internal/mutex_impl.h
Normal file
31
src/ulib/concorrency/internal/mutex_impl.h
Normal file
@ -0,0 +1,31 @@
|
||||
//
|
||||
// Created by Feng Zhang on 2023/12/12.
|
||||
//
|
||||
|
||||
#ifndef ULIB_SRC_ULIB_CONCORRENCY_INTERNAL_MUTEX_IMPL_H_
|
||||
#define ULIB_SRC_ULIB_CONCORRENCY_INTERNAL_MUTEX_IMPL_H_
|
||||
|
||||
#include <pthread.h>
|
||||
|
||||
namespace ulib {
|
||||
namespace detail {
|
||||
class MutexImpl {
|
||||
public:
|
||||
MutexImpl() { pthread_mutex_init(&mutex_, NULL); }
|
||||
|
||||
~MutexImpl() { pthread_mutex_destroy(&mutex_); }
|
||||
|
||||
void Lock() { pthread_mutex_lock(&mutex_); }
|
||||
|
||||
void Unlock() { pthread_mutex_unlock(&mutex_); }
|
||||
|
||||
bool TryLock() { return pthread_mutex_trylock(&mutex_) == 0; }
|
||||
|
||||
private:
|
||||
friend class ConditionVariableImpl;
|
||||
pthread_mutex_t mutex_;
|
||||
};
|
||||
} // namespace detail
|
||||
} // namespace ulib
|
||||
|
||||
#endif//ULIB_SRC_ULIB_CONCORRENCY_INTERNAL_MUTEX_IMPL_H_
|
36
src/ulib/concorrency/mutex.cpp
Normal file
36
src/ulib/concorrency/mutex.cpp
Normal file
@ -0,0 +1,36 @@
|
||||
//
|
||||
// Created by Feng Zhang on 2023/12/12.
|
||||
//
|
||||
|
||||
#include "mutex.h"
|
||||
#include "internal/mutex_impl.h"
|
||||
|
||||
namespace ulib {
|
||||
|
||||
Mutex::Mutex() : impl_(new detail::MutexImpl) {}
|
||||
|
||||
Mutex::~Mutex() { delete impl_; }
|
||||
|
||||
void
|
||||
Mutex::Lock()
|
||||
{
|
||||
impl_->Lock();
|
||||
}
|
||||
|
||||
void
|
||||
Mutex::Unlock()
|
||||
{
|
||||
impl_->Unlock();
|
||||
}
|
||||
|
||||
bool
|
||||
Mutex::TryLock()
|
||||
{
|
||||
return impl_->TryLock();
|
||||
}
|
||||
|
||||
MutexGuard::MutexGuard(Mutex &mutex) : mutex_(mutex) { mutex_.Lock(); }
|
||||
|
||||
MutexGuard::~MutexGuard() { mutex_.Unlock(); }
|
||||
|
||||
}// namespace ulib
|
43
src/ulib/concorrency/mutex.h
Normal file
43
src/ulib/concorrency/mutex.h
Normal file
@ -0,0 +1,43 @@
|
||||
//
|
||||
// Created by Feng Zhang on 2023/12/12.
|
||||
//
|
||||
|
||||
#ifndef ULIB_SRC_ULIB_CONCORRENCY_MUTEX_H_
|
||||
#define ULIB_SRC_ULIB_CONCORRENCY_MUTEX_H_
|
||||
|
||||
namespace ulib {
|
||||
|
||||
namespace detail {
|
||||
class MutexImpl;
|
||||
}
|
||||
class Mutex {
|
||||
public:
|
||||
Mutex();
|
||||
~Mutex();
|
||||
void Lock();
|
||||
void Unlock();
|
||||
bool TryLock();
|
||||
|
||||
private:
|
||||
Mutex(const Mutex &);
|
||||
Mutex &operator=(const Mutex &);
|
||||
|
||||
friend class ConditionVariable;
|
||||
detail::MutexImpl *impl_;
|
||||
};
|
||||
|
||||
class MutexGuard {
|
||||
public:
|
||||
MutexGuard(Mutex& );
|
||||
~MutexGuard();
|
||||
private:
|
||||
MutexGuard(const MutexGuard&);
|
||||
MutexGuard& operator=(const MutexGuard&);
|
||||
|
||||
friend class ConditionVariable;
|
||||
Mutex& mutex_;
|
||||
};
|
||||
|
||||
} // namespace ulib
|
||||
|
||||
#endif//ULIB_SRC_ULIB_CONCORRENCY_MUTEX_H_
|
@ -4,6 +4,8 @@ set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||
add_executable(ulib_test
|
||||
ulib/base/types_test.cpp
|
||||
ulib/log/log_test.cpp
|
||||
ulib/concorrency/mutex_test.cpp
|
||||
ulib/concorrency/event_test.cpp
|
||||
)
|
||||
target_link_libraries(ulib_test PRIVATE
|
||||
ulib
|
||||
|
62
tests/ulib/concorrency/event_test.cpp
Normal file
62
tests/ulib/concorrency/event_test.cpp
Normal file
@ -0,0 +1,62 @@
|
||||
#include <ulib/concorrency/condition_variable.h>
|
||||
#include <ulib/concorrency/mutex.h>
|
||||
#include <ulib/log/log.h>
|
||||
#include <gtest/gtest.h>
|
||||
#include <ulib/concorrency/event.h>
|
||||
#include <pthread.h>
|
||||
#include <vector>
|
||||
|
||||
class EventTest : public ::testing::Test {
|
||||
public:
|
||||
void SetUp() override
|
||||
{
|
||||
EXPECT_FALSE(event_());
|
||||
EXPECT_FALSE(event_.Wait(100));
|
||||
|
||||
consumer_count_ = 0;
|
||||
}
|
||||
|
||||
ulib::Event event_;
|
||||
ulib::Mutex mutex_;
|
||||
ulib::ConditionVariable cond_;
|
||||
|
||||
int32_t consumer_count_;
|
||||
};
|
||||
|
||||
void *
|
||||
Consumer(void *args)
|
||||
{
|
||||
EventTest *test = (EventTest *) args;
|
||||
{
|
||||
ulib::MutexGuard guard(test->mutex_);
|
||||
++test->consumer_count_;
|
||||
test->cond_.NotifyAll();
|
||||
}
|
||||
EXPECT_TRUE(test != NULL);
|
||||
test->event_.Wait();
|
||||
{
|
||||
ulib::MutexGuard guard(test->mutex_);
|
||||
--test->consumer_count_;
|
||||
test->cond_.NotifyAll();
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
TEST_F(EventTest, multi_thread_wait_event)
|
||||
{
|
||||
std::vector<pthread_t> threads(10);
|
||||
for (int i = 0; i < threads.size(); i++) { pthread_create(&threads[i], NULL, Consumer, this); }
|
||||
|
||||
ulib::MutexGuard guard(mutex_);
|
||||
while (consumer_count_ < threads.size()) { cond_.Wait(guard); }
|
||||
EXPECT_EQ(consumer_count_, threads.size());
|
||||
|
||||
{
|
||||
event_.Set();
|
||||
while (consumer_count_ > 0) { cond_.Wait(guard); }
|
||||
}
|
||||
|
||||
EXPECT_EQ(consumer_count_, 0);
|
||||
for (int i = 0; i < threads.size(); i++) { pthread_join(threads[i], NULL); }
|
||||
}
|
10
tests/ulib/concorrency/mutex_test.cpp
Normal file
10
tests/ulib/concorrency/mutex_test.cpp
Normal file
@ -0,0 +1,10 @@
|
||||
#include <gtest/gtest.h>
|
||||
#include <ulib/concorrency/mutex.h>
|
||||
|
||||
TEST(MutexTest, MutexTest)
|
||||
{
|
||||
ulib::Mutex mutex;
|
||||
EXPECT_TRUE(mutex.TryLock());
|
||||
EXPECT_FALSE(mutex.TryLock());
|
||||
mutex.Unlock();
|
||||
}
|
Loading…
Reference in New Issue
Block a user