Browse Source

V1.0.1| fix some bug

master
zhaohe 4 weeks ago
parent
commit
106c61dd09
  1. 4
      README.md
  2. 65
      src/components/thread/signal.cpp
  3. 11
      src/components/thread/signal.hpp
  4. 208
      src/components/thread/signal_test.cpp
  5. 2
      src/configs/version.hpp

4
README.md

@ -19,9 +19,9 @@
## 版本
```
v1| 初始化
V1.1| 修改默认日志配置文件
V1.0.1
修复用户将系统时间修改到过去, 导致出现部分逻辑假死的现象
```

65
src/components/thread/signal.cpp

@ -2,35 +2,78 @@
namespace iflytop {
namespace core {
using namespace std;
static struct timespec add_microseconds(struct timespec ts, long microseconds) {
// 将微秒转换为秒和纳秒
long extra_sec = microseconds / 1000000L;
long extra_nsec = (microseconds % 1000000L) * 1000L; // 微秒转纳秒
// 加到原时间上
ts.tv_sec += extra_sec;
ts.tv_nsec += extra_nsec;
// 处理纳秒进位
if (ts.tv_nsec >= 1000000000L) {
ts.tv_sec += ts.tv_nsec / 1000000000L;
ts.tv_nsec = ts.tv_nsec % 1000000000L;
}
return ts;
}
Singal::Singal() {
// Set clock to monotonic
pthread_condattr_init(&m_attr);
pthread_condattr_setclock(&m_attr, CLOCK_MONOTONIC);
pthread_cond_init(&m_cond, &m_attr);
}
bool Singal::sleep_for_us(int64_t us) {
std::unique_lock<std::mutex> lck(mtx_);
pthread_mutex_lock(&m_mutex);
if (signalNum != 0) {
signalNum--;
pthread_mutex_unlock(&m_mutex);
return true;
}
if (us < 0) return true;
if (cv_.wait_for(lck, std::chrono::microseconds(us)) ==
std::cv_status::timeout) {
if (signalNum != 0) signalNum--;
if (us < 0) {
pthread_mutex_unlock(&m_mutex);
return true;
}
// Wait on data
struct timespec ts;
clock_gettime(CLOCK_MONOTONIC, &ts);
ts = add_microseconds(ts, us);
int rc = pthread_cond_timedwait(&m_cond, &m_mutex, &ts);
if (rc == ETIMEDOUT) {
pthread_mutex_unlock(&m_mutex);
return true;
}
if (signalNum != 0) signalNum--;
pthread_mutex_unlock(&m_mutex);
return false;
};
bool Singal::sleep() {
std::unique_lock<std::mutex> lck(mtx_);
pthread_mutex_lock(&m_mutex);
if (signalNum != 0) {
signalNum--;
pthread_mutex_unlock(&m_mutex);
return true;
}
cv_.wait(lck);
pthread_cond_wait(&m_cond, &m_mutex);
if (signalNum != 0) signalNum--;
pthread_mutex_unlock(&m_mutex);
return true;
}
void Singal::notify() {
std::unique_lock<std::mutex> lck(mtx_);
cv_.notify_all();
pthread_mutex_lock(&m_mutex);
signalNum++;
pthread_mutex_unlock(&m_mutex);
pthread_cond_broadcast(&m_cond);
}
}
} // namespace zwsd
} // namespace core
} // namespace iflytop

11
src/components/thread/signal.hpp

@ -17,15 +17,18 @@ namespace iflytop {
namespace core {
using namespace std;
class Singal {
condition_variable cv_;
std::mutex mtx_;
atomic<int> signalNum = {0};
pthread_mutex_t m_mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t m_cond;
pthread_condattr_t m_attr;
public:
Singal();
bool sleep_for_us(int64_t us);
bool sleep();
void notify();
};
}
} // namespace zwsd
} // namespace core
} // namespace iflytop

208
src/components/thread/signal_test.cpp

@ -0,0 +1,208 @@
#ifdef SIGNAL_TEST
#include "signal.hpp"
#include <unistd.h>
#include <chrono>
#include <thread>
using namespace iflytop;
using namespace core;
using namespace std;
using namespace std::chrono;
int64_t getnow() { return duration_cast<microseconds>(steady_clock::now().time_since_epoch()).count(); }
#define TITLE(title) \
printf("========================================\n"); \
printf("= %s\n", title);
#define LOG(str, ...) printf("= " str "\n", ##__VA_ARGS__);
#define CTR() printf("=\n");
#define END() printf("=\n");
#define CHECK(passed) \
if (!(passed)) { \
printf("= check %s failed\n", #passed); \
exit(1); \
} else { \
printf("= check %s passed\n", #passed); \
}
#define CHECK_EQ(a, b, maxdiff) \
if (abs((a) - (b)) > (maxdiff)) { \
printf("= check %s == %s failed\n", #a, #b); \
exit(1); \
} else { \
printf("= check %s == %s passed\n", #a, #b); \
}
int main(int argc, char const *argv[]) {
/* code */
{
TITLE("=test sleep_for_us cost 1500000 us");
Singal signal;
int64_t now = getnow();
signal.sleep_for_us(1500 * 1000);
int64_t after = getnow();
int64_t real = after - now;
LOG("real:%ld, diff:%ld ms ", real, (real - 1500000) / 1000);
CTR();
CHECK(((real - 1500000) / 1000) < 5);
END();
}
printf("\n");
{
TITLE("test wake up \n");
Singal signal;
int64_t start, callwakeup, wakeup, jointime;
thread t1([&]() {
LOG("thread 1 start sleep");
signal.sleep();
wakeup = getnow();
LOG("thread 1 wake up");
});
start = getnow();
usleep(1000 * 1000); // 等待线程1开始睡眠
LOG("thread 2 start notify");
callwakeup = getnow();
signal.notify();
t1.join();
jointime = getnow();
int64_t notify_delay = wakeup - callwakeup;
int64_t sleep_time = wakeup - start;
LOG("thread 2 notify cost %ld us, thread 1 sleep %ld ms", notify_delay, sleep_time / 1000);
LOG("thread 2 join cost %ld ms", (jointime - callwakeup) / 1000);
CTR();
CHECK(notify_delay < 1000); // 通知延迟应该小于30us
CHECK(abs(sleep_time - 1000 * 1000) < 3000); // 睡眠时间应该大于1秒
CTR();
}
printf("\n");
{
TITLE("test wake up 2");
Singal signal;
int64_t start, callwakeup, wakeup, jointime;
thread t1([&]() {
LOG("thread 1 start sleep");
signal.sleep_for_us(10 * 1000 * 1000);
wakeup = getnow();
LOG("thread 1 wake up");
});
start = getnow();
usleep(1000 * 1000); // 等待线程1开始睡眠
LOG("thread 2 start notify");
callwakeup = getnow();
signal.notify();
t1.join();
jointime = getnow();
int64_t notify_delay = wakeup - callwakeup;
int64_t sleep_time = wakeup - start;
LOG("thread 2 notify cost %ld us, thread 1 sleep %ld ms", notify_delay, sleep_time / 1000);
LOG("thread 2 join cost %ld ms", (jointime - callwakeup) / 1000);
CTR();
CHECK_EQ(notify_delay, 0, 1000);
CHECK_EQ(sleep_time / 1000, 1000, 2);
CTR();
}
printf("\n");
{
TITLE("test wake up twice");
Singal signal;
int64_t start, callwakeup, wakeup, jointime;
thread t1([&]() {
LOG("thread 1 start sleep");
signal.sleep_for_us(3 * 1000 * 1000);
signal.sleep_for_us(3 * 1000 * 1000);
wakeup = getnow();
LOG("thread 1 wake up");
});
start = getnow();
usleep(1000 * 1000); // 等待线程1开始睡眠
LOG("thread 2 start notify");
callwakeup = getnow();
signal.notify();
signal.notify();
t1.join();
jointime = getnow();
int64_t notify_delay = wakeup - callwakeup;
int64_t sleep_time = wakeup - start;
LOG("thread 2 notify cost %ld us, thread 1 sleep %ld ms", notify_delay, sleep_time / 1000);
LOG("thread 2 join cost %ld ms", (jointime - callwakeup) / 1000);
CTR();
CHECK_EQ(notify_delay, 0, 1000);
CHECK_EQ(sleep_time / 1000, 1000, 2);
CTR();
}
printf("\n");
{
TITLE("test wake up twice 2");
Singal signal;
int64_t start, callwakeup, wakeup, jointime;
thread t1([&]() {
LOG("thread 1 start sleep");
signal.sleep_for_us(3 * 1000 * 1000);
signal.sleep_for_us(3 * 1000 * 1000);
wakeup = getnow();
LOG("thread 1 wake up");
});
start = getnow();
usleep(1000 * 1000); // 等待线程1开始睡眠
LOG("thread 2 start notify");
callwakeup = getnow();
signal.notify();
t1.join();
jointime = getnow();
int64_t notify_delay = wakeup - callwakeup;
int64_t sleep_time = wakeup - start;
LOG("thread 2 notify cost %ld us, thread 1 sleep %ld ms", notify_delay, sleep_time / 1000);
LOG("thread 2 join cost %ld ms", (jointime - callwakeup) / 1000);
CTR();
CHECK_EQ(notify_delay, 3000000, 1000); // 通知延迟应该等于3秒
CHECK_EQ(sleep_time / 1000, 4000, 2); // 睡眠时间应该等于4秒
CTR();
}
printf("\n");
printf("========================================\n");
printf("= All tests passed\n");
printf("========================================\n");
return 0;
}
#endif

2
src/configs/version.hpp

@ -1,2 +1,2 @@
#pragma once
#define VERSION "1.0.0"
#define VERSION "1.0.1"
Loading…
Cancel
Save