
פורסם: 02/05/2023 - 18:32
נושא ההודעה: אלטרנטיבה עבור Posix timers
|
אני מנסה לעשות timer ב־posix. מצאתי את והוא די עובד ומספק את הסחורה, למעט... כשאתה מפעיל את התוכנה תחת gdb מתקבל סיגנל וזה מקריס את התוכנה ואת gdb.
הפתרון הוא להוסיף כמה הגדרות ל־gdb כמתואר כאן: https://itecnote.com/tecnote/linux-program-terminating-on-receiving-signal-sig34-real-time-event-34/
... אבל לא בא לי בטוב. אני מחפש api אחר שאני אוכל להשתמש בו, כדי ליצור כמה timers - ושאוכל לחבר כל אחד אל אחר.
מה ההצעות? (בבקשה הצעות low level ללא frameworks כמו Qt או GTK).
הקוד שלי הוא:
קוד: |
struct Timer {
std::function<void()> callback;
int64_t millies;
bool repeating;
Timer();
auto start() -> void;
private:
static auto handler(int sig, siginfo_t *si, void *uc) -> void;
struct sigaction sa;
struct sigevent sev;
struct itimerspec its;
timer_t timerid;
};
Timer::Timer() {
sa.sa_flags = SA_SIGINFO;
sa.sa_sigaction = handler;
sigemptyset(&sa.sa_mask);
if (sigaction(SIGRTMIN, &sa, NULL) == -1) {
// errExit("sigaction");
return;
}
sev.sigev_notify = SIGEV_SIGNAL;
sev.sigev_signo = SIGRTMIN;
sev.sigev_value.sival_ptr = &timerid;
sev.sigev_value.sival_ptr = this;
if (timer_create(CLOCK_REALTIME, &sev, &timerid) == -1) {
// assert("timer_create");
return;
}
}
auto Timer::start() -> void {
its.it_value.tv_sec = millies / 1000;
its.it_value.tv_nsec = millies % 1000;
its.it_interval.tv_sec = its.it_value.tv_sec;
its.it_interval.tv_nsec = its.it_value.tv_nsec;
if (timer_settime(timerid, 0, &its, NULL) == -1) {
// error
}
}
auto Timer::handler(int sig, siginfo_t *si, void *uc) -> void {
Timer *timer = static_cast<Timer *>(si->si_value.sival_ptr);
timer->callback();
}
...
int main() {
Timer t1;
t1.millies = 2000;
t1.callback = [&i, &logger]() {
i++;
logger->info("Timer");
};
// or some other blocking function
while (1) {};
return ;
};
|
|
|
חזרה לתוכן הדיון |

פורסם: 02/05/2023 - 18:37
נושא ההודעה:
|
ליידע כללי, שאלתי את chat GPT בנושא, והוא הציע לעשות std::thread ובו לעשות לולאה, לחכות ואז לקרא לפונקציה שלי. זה בהחלט יעבוד, אבל מאוד לא חסכוני במשאבים - להרים thread עבור כל timer זה מאוד לא יעיל.
קוד: |
#include <iostream>
#include <chrono>
#include <atomic>
#include <thread>
std::atomic<bool> stop_flag(false);
void timer_callback()
{
std::cout << "Timer callback\n";
}
void start_timer(int interval, std::function<void()> callback)
{
while (!stop_flag.load())
{
std::chrono::milliseconds timespan(interval);
std::this_thread::sleep_for(timespan);
callback();
}
}
int main()
{
std::thread timer_thread(start_timer, 1000, timer_callback);
// Do some other work here
// ...
// Stop the timer thread
stop_flag.store(true);
timer_thread.join();
return 0;
}
|
|
|
חזרה לתוכן הדיון |

פורסם: 03/05/2023 - 08:37
נושא ההודעה:
|
מימוש שעובד (עברתי לקבל הודעה ב־thread במקום סיגנל, וזה מתנהג יותר טוב וגם מצריך פחות setup):
קוד: |
auto Timer::start() -> void {
struct sigevent sev;
memset(&sev, 0, sizeof sev);
sev.sigev_notify = SIGEV_THREAD;
sev.sigev_notify_function = &Timer::handler;
sev.sigev_value.sival_ptr = this;
timer_t timerid = 0;
int ret = timer_create(CLOCK_MONOTONIC, &sev, &timerid);
if (ret) {
ret = errno;
exit(1);
}
// Arm the timer to expire in the specified interval.
struct itimerspec trigger;
memset(&trigger, 0, sizeof trigger);
trigger.it_value.tv_sec = millies / 1000;
trigger.it_value.tv_nsec = millies % 1000;
trigger.it_interval.tv_sec = trigger.it_value.tv_sec;
trigger.it_interval.tv_nsec = trigger.it_value.tv_nsec;
ret = timer_settime(timerid, 0, &trigger, NULL);
if (ret) {
ret = errno;
exit(1);
}
}
auto Timer::handler(sigval sival_int) -> void {
Timer *timer = static_cast<Timer *>(sival_int.sival_ptr);
timer->callback();
}
|
מעניין כמה זה עובד ב־osx... אין לי אפשרות לבדוק 
|
|
חזרה לתוכן הדיון |

פורסם: 03/05/2023 - 15:42
נושא ההודעה: לא חושב שניתן להבטחי אותו thread גם ב std::async
|
לא חושב שניתן להבטחי אותו thread גם ב std::async הוא מחליט לבד ומעדיף thread נפרד
מה שנישמע לי שאנחנו מחפשים זה סיגנלים וסלוטים.
כאשר השעון רץ ס thread אחד ווה- סלוטים עונים לו באחר.
זה ניראה לי ממש מורכב לעשות דבר כזה, ולכן עדיף כבר לקחת מ Boost.
לא הצלחתי להריץ אץ מש ששמתה - לא הבנתי איך לכתוב את זה ב- main()
# יכול להיות שאני ממש טועה,
אם ניתן להבטיח ב c++ שזה ירוץ ויחקה על אותו thread כמו ב Javascript
|
|
חזרה לתוכן הדיון |

פורסם: 03/05/2023 - 15:54
נושא ההודעה: time.h לא מכיל את כל ההגדרות כמו בלינוקס וזה לא מתקמפל
|
```
[build] /Volumes/RAM_Disk_4G/f/main.cpp:37:23: error: field has incomplete type 'struct itimerspec'
[build] struct itimerspec its;
[build] ^
```
הדרך הכי נכונה היא לבחון איך boost עושה את זה,
https://www.boost.org/doc/libs/1_66_0/doc/html/boost_asio/tutorial/tuttimer2.html
|
|
חזרה לתוכן הדיון |

פורסם: 03/05/2023 - 16:10
נושא ההודעה: כשאני חושב על זה - יש חשיבות למה שאתה מנשה לעשות
|
אם נניח ויש לך כרטיס קול מיותר - או אפילו עם חיבור WC (קואקס) לשעון אטומי
אז אולי נכון לייצר טיימר זמן אמת עבור המחשב, ואז נוכל לסנכרן דברים על ספירה של
frames.
ואת ההבקשות וההוראות הוא ייתן ויקבל מ devices of mkfifo.
אין סיבה שב 2023 כשהעולם כולכך מתקדם, מחשב אישי לא יעבוד עם זמן אמת אמיתי.....
|
|
חזרה לתוכן הדיון |

פורסם: 04/05/2023 - 13:22
נושא ההודעה:
|
ניסית ב gdb לכתוב
קוד: | set unwindonsignal off |
?
במידה ואתה סוגר את האפשרות, האם זה עדיין מקריס?
|
|
חזרה לתוכן הדיון |

פורסם: 04/05/2023 - 14:55
נושא ההודעה:
|
Anonymous : | ניסית ב gdb לכתוב
קוד: | set unwindonsignal off |
?
במידה ואתה סוגר את האפשרות, האם זה עדיין מקריס? |
לא טרחתי. אבל אני חושב שאם אני צריך לעשות משהו בסביבת פיתוח שלי, כדי לקדם את התוכנה - אז זה לא פתרון טוב.
כמו שתכתבי - במקום לשהתמש ב־SIGEV_SIGNAL עברתי להשתמש ב־SIGEV_THREAD וקיבלתי את התוצאה הרצויה. תודה.
|
|
חזרה לתוכן הדיון |
|