mirror of
https://github.com/mutouyun/cpp-ipc.git
synced 2025-12-07 01:06:45 +08:00
merge issue-61; add condition for linux
This commit is contained in:
parent
4ca300b3e5
commit
0cccdac868
39
include/libipc/condition.h
Normal file
39
include/libipc/condition.h
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <cstdint> // std::uint64_t
|
||||||
|
|
||||||
|
#include "libipc/export.h"
|
||||||
|
#include "libipc/def.h"
|
||||||
|
#include "libipc/mutex.h"
|
||||||
|
|
||||||
|
namespace ipc {
|
||||||
|
namespace sync {
|
||||||
|
|
||||||
|
class IPC_EXPORT condition {
|
||||||
|
condition(condition const &) = delete;
|
||||||
|
condition &operator=(condition const &) = delete;
|
||||||
|
|
||||||
|
public:
|
||||||
|
condition();
|
||||||
|
explicit condition(char const *name);
|
||||||
|
~condition();
|
||||||
|
|
||||||
|
void const *native() const noexcept;
|
||||||
|
void *native() noexcept;
|
||||||
|
|
||||||
|
bool valid() const noexcept;
|
||||||
|
|
||||||
|
bool open(char const *name) noexcept;
|
||||||
|
void close() noexcept;
|
||||||
|
|
||||||
|
bool wait(ipc::sync::mutex &mtx, std::uint64_t tm = ipc::invalid_value) noexcept;
|
||||||
|
bool notify() noexcept;
|
||||||
|
bool broadcast() noexcept;
|
||||||
|
|
||||||
|
private:
|
||||||
|
class condition_;
|
||||||
|
condition_* p_;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace sync
|
||||||
|
} // namespace ipc
|
||||||
@ -5,7 +5,8 @@ if(UNIX)
|
|||||||
else()
|
else()
|
||||||
file(GLOB SRC_FILES ${LIBIPC_PROJECT_DIR}/src/libipc/platform/*_win.cpp)
|
file(GLOB SRC_FILES ${LIBIPC_PROJECT_DIR}/src/libipc/platform/*_win.cpp)
|
||||||
endif()
|
endif()
|
||||||
aux_source_directory(${LIBIPC_PROJECT_DIR}/src SRC_FILES)
|
aux_source_directory(${LIBIPC_PROJECT_DIR}/src/libipc SRC_FILES)
|
||||||
|
aux_source_directory(${LIBIPC_PROJECT_DIR}/src/libipc/sync SRC_FILES)
|
||||||
|
|
||||||
file(GLOB HEAD_FILES
|
file(GLOB HEAD_FILES
|
||||||
${LIBIPC_PROJECT_DIR}/include/libipc/*.h
|
${LIBIPC_PROJECT_DIR}/include/libipc/*.h
|
||||||
@ -37,8 +38,8 @@ set_target_properties(${PROJECT_NAME}
|
|||||||
# set version
|
# set version
|
||||||
set_target_properties(${PROJECT_NAME}
|
set_target_properties(${PROJECT_NAME}
|
||||||
PROPERTIES
|
PROPERTIES
|
||||||
VERSION 1.0.0
|
VERSION 1.1.0
|
||||||
SOVERSION 1)
|
SOVERSION 2)
|
||||||
|
|
||||||
target_include_directories(${PROJECT_NAME}
|
target_include_directories(${PROJECT_NAME}
|
||||||
PUBLIC ${LIBIPC_PROJECT_DIR}/include
|
PUBLIC ${LIBIPC_PROJECT_DIR}/include
|
||||||
|
|||||||
@ -1,12 +1,15 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
|
#include <cstring>
|
||||||
|
|
||||||
#include <pthread.h>
|
#include <pthread.h>
|
||||||
|
|
||||||
#include "libipc/utility/log.h"
|
|
||||||
#include "libipc/platform/get_wait_time.h"
|
#include "libipc/platform/get_wait_time.h"
|
||||||
|
#include "libipc/utility/log.h"
|
||||||
|
#include "libipc/utility/scope_guard.h"
|
||||||
#include "libipc/mutex.h"
|
#include "libipc/mutex.h"
|
||||||
|
#include "libipc/shm.h"
|
||||||
|
|
||||||
namespace ipc {
|
namespace ipc {
|
||||||
namespace detail {
|
namespace detail {
|
||||||
@ -89,7 +92,7 @@ public:
|
|||||||
return true;
|
return true;
|
||||||
case invalid_value: {
|
case invalid_value: {
|
||||||
int eno;
|
int eno;
|
||||||
if ((eno = ::pthread_cond_wait(cond_, mtx.native())) != 0) {
|
if ((eno = ::pthread_cond_wait(cond_, static_cast<pthread_mutex_t *>(mtx.native()))) != 0) {
|
||||||
ipc::error("fail pthread_cond_wait[%d]\n", eno);
|
ipc::error("fail pthread_cond_wait[%d]\n", eno);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -98,7 +101,7 @@ public:
|
|||||||
default: {
|
default: {
|
||||||
auto ts = detail::make_timespec(tm);
|
auto ts = detail::make_timespec(tm);
|
||||||
int eno;
|
int eno;
|
||||||
if ((eno = ::pthread_cond_timedwait(cond_, mtx.native(), &ts)) != 0) {
|
if ((eno = ::pthread_cond_timedwait(cond_, static_cast<pthread_mutex_t *>(mtx.native()), &ts)) != 0) {
|
||||||
if (eno != ETIMEDOUT) {
|
if (eno != ETIMEDOUT) {
|
||||||
ipc::error("fail pthread_cond_timedwait[%d]: tm = %zd, tv_sec = %ld, tv_nsec = %ld\n",
|
ipc::error("fail pthread_cond_timedwait[%d]: tm = %zd, tv_sec = %ld, tv_nsec = %ld\n",
|
||||||
eno, tm, ts.tv_sec, ts.tv_nsec);
|
eno, tm, ts.tv_sec, ts.tv_nsec);
|
||||||
|
|||||||
70
src/libipc/sync/condition.cpp
Normal file
70
src/libipc/sync/condition.cpp
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
|
||||||
|
#include "libipc/condition.h"
|
||||||
|
|
||||||
|
#include "libipc/utility/pimpl.h"
|
||||||
|
#include "libipc/memory/resource.h"
|
||||||
|
#include "libipc/platform/detail.h"
|
||||||
|
#if defined(IPC_OS_WINDOWS_)
|
||||||
|
#include "libipc/platform/condition_win.h"
|
||||||
|
#elif defined(IPC_OS_LINUX_)
|
||||||
|
#include "libipc/platform/condition_linux.h"
|
||||||
|
#else/*linux*/
|
||||||
|
# error "Unsupported platform."
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace ipc {
|
||||||
|
namespace sync {
|
||||||
|
|
||||||
|
class condition::condition_ : public ipc::pimpl<condition_> {
|
||||||
|
public:
|
||||||
|
ipc::detail::sync::condition cond_;
|
||||||
|
};
|
||||||
|
|
||||||
|
condition::condition()
|
||||||
|
: p_(p_->make()) {
|
||||||
|
}
|
||||||
|
|
||||||
|
condition::condition(char const * name)
|
||||||
|
: condition() {
|
||||||
|
open(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
condition::~condition() {
|
||||||
|
close();
|
||||||
|
p_->clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
void const *condition::native() const noexcept {
|
||||||
|
return impl(p_)->cond_.native();
|
||||||
|
}
|
||||||
|
|
||||||
|
void *condition::native() noexcept {
|
||||||
|
return impl(p_)->cond_.native();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool condition::valid() const noexcept {
|
||||||
|
return impl(p_)->cond_.valid();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool condition::open(char const *name) noexcept {
|
||||||
|
return impl(p_)->cond_.open(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
void condition::close() noexcept {
|
||||||
|
impl(p_)->cond_.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool condition::wait(ipc::sync::mutex &mtx, std::uint64_t tm) noexcept {
|
||||||
|
return impl(p_)->cond_.wait(mtx, tm);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool condition::notify() noexcept {
|
||||||
|
return impl(p_)->cond_.notify();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool condition::broadcast() noexcept {
|
||||||
|
return impl(p_)->cond_.broadcast();
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace sync
|
||||||
|
} // namespace ipc
|
||||||
@ -99,22 +99,6 @@ public:
|
|||||||
}
|
}
|
||||||
} const data_set__;
|
} const data_set__;
|
||||||
|
|
||||||
#define IPC_ASSERT_TRUE(condition) \
|
|
||||||
do { \
|
|
||||||
bool check = !!(condition); \
|
|
||||||
GTEST_TEST_BOOLEAN_(check, #condition, false, true, \
|
|
||||||
GTEST_NONFATAL_FAILURE_); \
|
|
||||||
if (!check) return; \
|
|
||||||
} while (0)
|
|
||||||
|
|
||||||
#define IPC_ASSERT_FALSE(condition) \
|
|
||||||
do { \
|
|
||||||
bool check = !!(condition); \
|
|
||||||
GTEST_TEST_BOOLEAN_(!check, #condition, true, false, \
|
|
||||||
GTEST_NONFATAL_FAILURE_); \
|
|
||||||
if (check) return; \
|
|
||||||
} while (0)
|
|
||||||
|
|
||||||
template <relat Rp, relat Rc, trans Ts, typename Que = chan<Rp, Rc, Ts>>
|
template <relat Rp, relat Rc, trans Ts, typename Que = chan<Rp, Rc, Ts>>
|
||||||
void test_sr(char const * name, int s_cnt, int r_cnt) {
|
void test_sr(char const * name, int s_cnt, int r_cnt) {
|
||||||
ipc_ut::sender().start(static_cast<std::size_t>(s_cnt));
|
ipc_ut::sender().start(static_cast<std::size_t>(s_cnt));
|
||||||
@ -126,10 +110,10 @@ void test_sr(char const * name, int s_cnt, int r_cnt) {
|
|||||||
for (int k = 0; k < s_cnt; ++k) {
|
for (int k = 0; k < s_cnt; ++k) {
|
||||||
ipc_ut::sender() << [name, &sw, r_cnt, k] {
|
ipc_ut::sender() << [name, &sw, r_cnt, k] {
|
||||||
Que que { name, ipc::sender };
|
Que que { name, ipc::sender };
|
||||||
IPC_ASSERT_TRUE(que.wait_for_recv(r_cnt));
|
ASSERT_TRUE(que.wait_for_recv(r_cnt));
|
||||||
sw.start();
|
sw.start();
|
||||||
for (int i = 0; i < (int)data_set__.get().size(); ++i) {
|
for (int i = 0; i < (int)data_set__.get().size(); ++i) {
|
||||||
IPC_ASSERT_TRUE(que.send(data_set__.get()[i]));
|
ASSERT_TRUE(que.send(data_set__.get()[i]));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -139,17 +123,17 @@ void test_sr(char const * name, int s_cnt, int r_cnt) {
|
|||||||
Que que { name, ipc::receiver };
|
Que que { name, ipc::receiver };
|
||||||
for (;;) {
|
for (;;) {
|
||||||
rand_buf got { que.recv() };
|
rand_buf got { que.recv() };
|
||||||
IPC_ASSERT_FALSE(got.empty());
|
ASSERT_FALSE(got.empty());
|
||||||
int i = got.get_id();
|
int i = got.get_id();
|
||||||
if (i == -1) {
|
if (i == -1) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
IPC_ASSERT_TRUE((i >= 0) && (i < (int)data_set__.get().size()));
|
ASSERT_TRUE((i >= 0) && (i < (int)data_set__.get().size()));
|
||||||
auto const &data_set = data_set__.get()[i];
|
auto const &data_set = data_set__.get()[i];
|
||||||
if (data_set != got) {
|
if (data_set != got) {
|
||||||
printf("data_set__.get()[%d] != got, size = %zd/%zd\n",
|
printf("data_set__.get()[%d] != got, size = %zd/%zd\n",
|
||||||
i, data_set.size(), got.size());
|
i, data_set.size(), got.size());
|
||||||
IPC_ASSERT_TRUE(false);
|
ASSERT_TRUE(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -157,7 +141,7 @@ void test_sr(char const * name, int s_cnt, int r_cnt) {
|
|||||||
|
|
||||||
ipc_ut::sender().wait_for_done();
|
ipc_ut::sender().wait_for_done();
|
||||||
Que que { name };
|
Que que { name };
|
||||||
IPC_ASSERT_TRUE(que.wait_for_recv(r_cnt));
|
ASSERT_TRUE(que.wait_for_recv(r_cnt));
|
||||||
for (int k = 0; k < r_cnt; ++k) {
|
for (int k = 0; k < r_cnt; ++k) {
|
||||||
que.send(rand_buf{msg_head{-1}});
|
que.send(rand_buf{msg_head{-1}});
|
||||||
}
|
}
|
||||||
|
|||||||
@ -3,6 +3,8 @@
|
|||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
|
#include <deque>
|
||||||
|
#include <cstdio>
|
||||||
|
|
||||||
#include "test.h"
|
#include "test.h"
|
||||||
|
|
||||||
@ -57,7 +59,7 @@ TEST(Sync, Mutex) {
|
|||||||
ipc::sync::mutex lock;
|
ipc::sync::mutex lock;
|
||||||
EXPECT_TRUE(lock.open("test-mutex-robust"));
|
EXPECT_TRUE(lock.open("test-mutex-robust"));
|
||||||
std::thread{[] {
|
std::thread{[] {
|
||||||
ipc::sync::mutex lock{"test-mutex-robust"};
|
ipc::sync::mutex lock {"test-mutex-robust"};
|
||||||
EXPECT_TRUE(lock.valid());
|
EXPECT_TRUE(lock.valid());
|
||||||
EXPECT_TRUE(lock.lock());
|
EXPECT_TRUE(lock.lock());
|
||||||
}}.join();
|
}}.join();
|
||||||
@ -68,7 +70,7 @@ TEST(Sync, Mutex) {
|
|||||||
EXPECT_TRUE(lock.lock());
|
EXPECT_TRUE(lock.lock());
|
||||||
i = 100;
|
i = 100;
|
||||||
auto t2 = std::thread{[&i] {
|
auto t2 = std::thread{[&i] {
|
||||||
ipc::sync::mutex lock{"test-mutex-robust"};
|
ipc::sync::mutex lock {"test-mutex-robust"};
|
||||||
EXPECT_TRUE(lock.valid());
|
EXPECT_TRUE(lock.valid());
|
||||||
EXPECT_FALSE(lock.try_lock());
|
EXPECT_FALSE(lock.try_lock());
|
||||||
EXPECT_TRUE(lock.lock());
|
EXPECT_TRUE(lock.lock());
|
||||||
@ -88,12 +90,71 @@ TEST(Sync, Semaphore) {
|
|||||||
ipc::sync::semaphore sem;
|
ipc::sync::semaphore sem;
|
||||||
EXPECT_TRUE(sem.open("test-sem"));
|
EXPECT_TRUE(sem.open("test-sem"));
|
||||||
std::thread{[] {
|
std::thread{[] {
|
||||||
ipc::sync::semaphore sem{"test-sem"};
|
ipc::sync::semaphore sem {"test-sem"};
|
||||||
EXPECT_TRUE(sem.post(10));
|
EXPECT_TRUE(sem.post(1000));
|
||||||
}}.join();
|
}}.join();
|
||||||
|
|
||||||
for (int i = 0; i < 10; ++i) {
|
for (int i = 0; i < 1000; ++i) {
|
||||||
EXPECT_TRUE(sem.wait(0));
|
EXPECT_TRUE(sem.wait(0));
|
||||||
}
|
}
|
||||||
EXPECT_FALSE(sem.wait(0));
|
EXPECT_FALSE(sem.wait(0));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#include "libipc/condition.h"
|
||||||
|
|
||||||
|
TEST(Sync, Condition) {
|
||||||
|
ipc::sync::condition cond;
|
||||||
|
EXPECT_TRUE(cond.open("test-cond"));
|
||||||
|
ipc::sync::mutex lock;
|
||||||
|
EXPECT_TRUE(lock.open("test-mutex"));
|
||||||
|
std::deque<int> que;
|
||||||
|
|
||||||
|
auto job = [&que](int num) {
|
||||||
|
ipc::sync::condition cond {"test-cond"};
|
||||||
|
ipc::sync::mutex lock {"test-mutex"};
|
||||||
|
for (;;) {
|
||||||
|
int val = 0;
|
||||||
|
{
|
||||||
|
std::lock_guard<ipc::sync::mutex> guard {lock};
|
||||||
|
while (que.empty()) {
|
||||||
|
ASSERT_TRUE(cond.wait(lock));
|
||||||
|
}
|
||||||
|
val = que.front();
|
||||||
|
que.pop_front();
|
||||||
|
}
|
||||||
|
if (val == 0) {
|
||||||
|
std::printf("test-cond-%d: exit.\n", num);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
std::printf("test-cond-%d: %d\n", num, val);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
std::thread test_cond1 {job, 1};
|
||||||
|
std::thread test_cond2 {job, 2};
|
||||||
|
|
||||||
|
for (int i = 1; i < 100; ++i) {
|
||||||
|
{
|
||||||
|
std::lock_guard<ipc::sync::mutex> guard {lock};
|
||||||
|
que.push_back(i);
|
||||||
|
}
|
||||||
|
cond.notify();
|
||||||
|
std::this_thread::sleep_for(std::chrono::milliseconds(20));
|
||||||
|
}
|
||||||
|
for (int i = 1; i < 100; ++i) {
|
||||||
|
{
|
||||||
|
std::lock_guard<ipc::sync::mutex> guard {lock};
|
||||||
|
que.push_back(i);
|
||||||
|
}
|
||||||
|
cond.broadcast();
|
||||||
|
std::this_thread::sleep_for(std::chrono::milliseconds(20));
|
||||||
|
}
|
||||||
|
{
|
||||||
|
std::lock_guard<ipc::sync::mutex> guard {lock};
|
||||||
|
que.push_back(0);
|
||||||
|
que.push_back(0);
|
||||||
|
}
|
||||||
|
cond.broadcast();
|
||||||
|
|
||||||
|
test_cond1.join();
|
||||||
|
test_cond2.join();
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user