Skip to content

Commit

Permalink
修复执行std::function时同时可能覆写导致的bug
Browse files Browse the repository at this point in the history
  • Loading branch information
xia-chu committed Jan 19, 2025
1 parent 8c2a2f2 commit 0eb87b2
Show file tree
Hide file tree
Showing 3 changed files with 82 additions and 6 deletions.
2 changes: 1 addition & 1 deletion src/Network/BufferSock.h
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ class BufferSock : public Buffer {
class BufferList : public noncopyable {
public:
using Ptr = std::shared_ptr<BufferList>;
using SendResult = std::function<void(const Buffer::Ptr &buffer, bool send_success)>;
using SendResult = toolkit::function_safe<void(const Buffer::Ptr &buffer, bool send_success)>;

BufferList() = default;
virtual ~BufferList() = default;
Expand Down
10 changes: 5 additions & 5 deletions src/Network/Socket.h
Original file line number Diff line number Diff line change
Expand Up @@ -315,20 +315,20 @@ class Socket : public std::enable_shared_from_this<Socket>, public noncopyable,
//接收数据回调 [AUTO-TRANSLATED:e3b7ff16]
//Receive data callback
using onReadCB = std::function<void(Buffer::Ptr &buf, struct sockaddr *addr, int addr_len)>;
using onMultiReadCB = std::function<void(Buffer::Ptr *buf, struct sockaddr_storage *addr, size_t count)>;
using onMultiReadCB = toolkit::function_safe<void(Buffer::Ptr *buf, struct sockaddr_storage *addr, size_t count)>;

//发生错误回调 [AUTO-TRANSLATED:d6897b99]
//Error callback
using onErrCB = std::function<void(const SockException &err)>;
using onErrCB = toolkit::function_safe<void(const SockException &err)>;
//tcp监听接收到连接请求 [AUTO-TRANSLATED:c4e1b206]
//TCP listen receives a connection request
using onAcceptCB = std::function<void(Socket::Ptr &sock, std::shared_ptr<void> &complete)>;
using onAcceptCB = toolkit::function_safe<void(Socket::Ptr &sock, std::shared_ptr<void> &complete)>;
//socket发送缓存清空事件,返回true代表下次继续监听该事件,否则停止 [AUTO-TRANSLATED:2dd1c036]
//Socket send buffer is cleared event, returns true to continue listening for the event next time, otherwise stops
using onFlush = std::function<bool()>;
using onFlush = toolkit::function_safe<bool()>;
//在接收到连接请求前,拦截Socket默认生成方式 [AUTO-TRANSLATED:2f07f268]
//Intercept the default generation method of the Socket before receiving a connection request
using onCreateSocket = std::function<Ptr(const EventPoller::Ptr &poller)>;
using onCreateSocket = toolkit::function_safe<Ptr(const EventPoller::Ptr &poller)>;
//发送buffer成功与否回调 [AUTO-TRANSLATED:4db5efb8]
//Send buffer success or failure callback
using onSendResult = BufferList::SendResult;
Expand Down
76 changes: 76 additions & 0 deletions src/Util/util.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
#include <atomic>
#include <unordered_map>
#include "function_traits.h"
#include "onceToken.h"
#if defined(_WIN32)
#undef FD_SETSIZE
//修改默认64为1024路 [AUTO-TRANSLATED:90567e14]
Expand Down Expand Up @@ -504,6 +505,81 @@ class AnyStorage : public std::unordered_map<std::string, Any> {
using Ptr = std::shared_ptr<AnyStorage>;
};

template <class R, class... ArgTypes>
class function_safe;

template <typename R, typename... ArgTypes>
class function_safe<R(ArgTypes...)> {
public:
using func = std::function<R(ArgTypes...)>;
using this_type = function_safe<R(ArgTypes...)>;

template <class F>
using enable_if_not_this = typename std::enable_if<!std::is_same<this_type, typename std::decay<F>::type>::value, typename std::decay<F>::type>::type;

R operator()(ArgTypes... args) const {
onceToken token([&]() { _doing = true; checkUpdate(); }, [&]() { checkUpdate(); _doing = false; });
if (!_impl) {
throw std::invalid_argument("try to invoke a empty functional");
}
return _impl(std::forward<ArgTypes>(args)...);
}

function_safe(std::nullptr_t) {
update(func{});
}

function_safe &operator=(std::nullptr_t) {
update(func{});
return *this;
}

template <typename F, typename = enable_if_not_this<F>>
function_safe(F &&f) {
update(func { std::forward<F>(f) });
}

template <typename F, typename = enable_if_not_this<F>>
this_type &operator=(F &&f) {
update(func { std::forward<F>(f) });
return *this;
}

function_safe() = default;
function_safe(this_type &&) = default;
function_safe(const this_type &) = default;
this_type &operator=(this_type &&) = default;
this_type &operator=(const this_type &) = default;

operator bool() const { return _update ? (bool)_tmp : (bool)_impl; }

private:
void checkUpdate() const {
if (_update) {
_update = false;
_impl = std::move(_tmp);
}
}
void update(func in) {
if (!_doing) {
// 没在执行中,那么立即覆写
_impl = std::move(in);
_tmp = nullptr;
_update = false;
} else {
// 正在执行中,延后覆写
_tmp = std::move(in);
_update = true;
}
}

private:
mutable bool _update = false;
mutable bool _doing = false;
mutable func _tmp;
mutable func _impl;
};

} // namespace toolkit

#ifdef __cplusplus
Expand Down

0 comments on commit 0eb87b2

Please sign in to comment.