I have a CFRunLoopTimer created within a C++ class as shown below:
#import <CoreFoundation/CoreFoundation.h>
void cClass::StartTimer()
{
if(!mActiveSenseTimer)
{
CFTimeInterval TIMER_INTERVAL = 5;
CFRunLoopTimerContext TimerContext = {0, this, NULL, NULL, NULL};
CFAbsoluteTime FireTime = CFAbsoluteTimeGetCurrent() + TIMER_INTERVAL;
mTimer = CFRunLoopTimerCreate(kCFAllocatorDefault,
FireTime,
0, 0, 0,
ActiveSenseTimerCallback,
&TimerContext);
NSLog(#"RunLoop:0x%x, TimerIsValid:%d, TimeIsNow:%f, TimerWillFireAt:%f",
CFRunLoopGetCurrent(),
CFRunLoopTimerIsValid(mActiveSenseTimer),
CFAbsoluteTimeGetCurrent(),
FireTime);
}
}
void ActiveSenseTimerCallback(CFRunLoopTimerRef timer, void *info)
{
NSLog(#"Timeout");
CFRunLoopTimerContext TimerContext;
TimerContext.version = 0;
CFRunLoopTimerGetContext(timer, &TimerContext);
((cClass *)TimerContext.info)->Timeout();
}
Calling cClass::StartTimer() results in the following log output:
RunLoop:0x7655d60, TimerIsValid:1, TimeIsNow:389196910.537962, TimerWillFireAt:389196915.537956
However, my timer never fires. Any ideas why?
Quote from the docs
A timer needs to be added to a run loop mode before it will fire. To add the timer to a run loop, use CFRunLoopAddTimer. A timer can be registered to only one run loop at a time, although it can be in multiple modes within that run loop.
Also make sure your run loop doesn't die before the timer fires.
Related
So for a report I'm trying to time the number of cycles it takes to execute a couple seperate functions in a program running on an ESP32, using freeRTOS. The code looks something like this with init_input_generator() being the first function called, here i'm timing onesecwindow.fifo_iir_filter_datapoint():
float geninputarray[SAMPLING_RATE]; //stores the values of an artificial signal we can use to test the algorithm
fifo_buffer onesecwindow = fifo_buffer(SAMPLING_RATE);
esp_err_t init_input_generator() {
dsps_tone_gen_f32(geninputarray, SAMPLING_RATE, 4, 0.04, 0); //10Hz
TimerHandle_t input_signal_timer =
xTimerCreate("input_timer", pdMS_TO_TICKS(10), pdTRUE, (void *)0, input_generator_callback);
xTimerStart(input_signal_timer, 0);
return ESP_OK;
}
void input_generator_callback(TimerHandle_t xTimer)
{
xTaskCreatePinnedToCore(
input_counter,
"input_generator",
4096,
NULL,
tskIDLE_PRIORITY + 11,
NULL,
PRO_CPU_NUM);
}
void input_counter(TimerHandle_t xTimer)
{
stepcounter = (stepcounter + 1) % SAMPLING_RATE;
insert_new_data(geninputarray[stepcounter]);
vTaskDelete(nullptr); // to gracefully end the task as returning is not allowed
}
esp_err_t insert_new_data(float datapoint)
{
onesecwindow.fifo_write(datapoint); // writes the new datapoint into the onesec window
unsigned int start_time = dsp_get_cpu_cycle_count();
onesecwindow.fifo_iir_filter_datapoint();
unsigned int end_time = dsp_get_cpu_cycle_count();
printf("%i\n", (end_time-start_time));
}
The thing that i'm noticing is that whenever I change the xTimerPeriodInTicks to a larger number, I get significantly longer time results, which just really confuses me and get's in the way of proper timing. Although the function doesn't scale with the SAMPLING_RATE and thus should give quite consistent results for each loop, output in cycles with a 10ms timer period looks something like this (every 5 or 6 "loops" for some reason it's longer):
1567, 630, 607, 624, 591, 619, 649, 1606, 607
with a 40ms timer period I get this as a typical output:
1904, 600, 1894, 616, 1928, 1928, 607, 1897, 628
As such I'm confused by the output, as they use the same freeRTOS taskcreate to run with the same priority on the same core, I don't see why there would be any difference. Perhaps I'm misunderstanding something basic/fundamental here so any help would be greatly appreciated.
Update
So based on the comments by #Tarmo i have restructured to approach to having a recurring task, unfortunately the output still seems to suffer from the same problem. The code now looks like this:
#include <esp_dsp.h> //Official ESP-DSP library
float geninputarray[SAMPLING_RATE]; //stores the values of an artificial signal we can use to test the algorithm
fifo_buffer onesecwindow = fifo_buffer(SAMPLING_RATE);
esp_err_t init_input_generator() {
dsps_tone_gen_f32(geninputarray, SAMPLING_RATE, 4, 0.04, 0); //10Hz
xTaskCreatePinnedToCore(
input_counter, // the actual function to be called
"input_generator",
4096,
NULL,
tskIDLE_PRIORITY + 5,
NULL,
APP_CPU_NUM);
return ESP_OK;
}
void input_counter(TimerHandle_t xTimer)
{
while (true)
{
stepcounter = (stepcounter + 1) % SAMPLING_RATE;
insert_new_data(geninputarray[stepcounter]);
vTaskDelay(4);
}
}
esp_err_t insert_new_data(float datapoint)
{
onesecwindow.fifo_write(datapoint); // writes the new datapoint into the onesec window
unsigned int start_time = dsp_get_cpu_cycle_count();
onesecwindow.fifo_iir_filter_datapoint();
unsigned int end_time = dsp_get_cpu_cycle_count();
printf("%i\n", (end_time-start_time));
}
I am trying to share data between 2 FreeRTOS tasks. My approach for this is to create a struct for the tasks' pvParameters that contains a std::shared_pointer.
My task creation looks like this:
auto shared_value = std::make_shared<int8_t>(-1);
auto paramsA = SharedValParams(shared_value);
xTaskCreate(taskA,
"Task A",
4000,
(void *)¶msA ,
1,
NULL);
auto paramsB = SharedValParams(shared_value);
xTaskCreate(taskB,
"Task B",
4000,
(void *)¶msB,
1,
NULL);
I'm currently trying to modify this value
void taskA(void *params)
{
for (;;)
{
*((SharedValParams*)params)->shared_val= 5;
Serial.printf("Shared val is now %d\n",
*(*(SharedValParams*)params).shared_val.get());
vTaskDelay(1000/ portTICK_PERIOD_MS);
}
}
The first couple executions of taskA, shared_val is printed as 5. Great! However, after this shared_val is set to 0, or at least that's what is being printed. I've yet to implement this in taskB, so nothing else accesses or modifies shared_val. I'm unsure as to why this is happening, especially when the default value of shared_val is -1.
In the future once I resolve this issue, I will surround shared_val in a mutex, but for now, I cannot reliably set the value. The motivation behind passing this as a param, is to keep the value scoped between relevant tasks.
I am following the example in https://learn.microsoft.com/en-gb/windows/win32/api/iphlpapi/nf-iphlpapi-getpertcp6connectionestats?redirectedfrom=MSDN to get the TCP statistics. Although, I got it working and get the statistics in the first place, still I want to record them every a time interval (which I haven't managed to do so), and I have the following questions.
The SetPerTcpConnectionEStats () fails with status != NO_ERROR and equal to 5. Although, it fails, I can get the statistics. Why?
I want to get the statistics every, let's say 1 second. I have tried two different ways; a) to use a while loop and use a std::this_thread::sleep_for(1s), where I could get the statistics every ~1sec, but the whole app was stalling (is it because of the this), I supposed that I am blocking the operation of the main, and b) (since a) failed) I tried to call TcpStatistics() from another function (in different class) that is triggered every 1 sec (I store clientConnectRow to a global var). However, in that case (b), GetPerTcpConnectionEStats() fails with winStatus = 1214 (ERROR_INVALID_NETNAME) and of course TcpStatistics() cannot get any of the statistics.
a)
ClassB::ClassB()
{
UINT winStatus = GetTcpRow(localPort, hostPort, MIB_TCP_STATE_ESTAB, (PMIB_TCPROW)clientConnectRow);
ToggleAllEstats(clientConnectRow, TRUE);
thread t1(&ClassB::TcpStatistics, this, clientConnectRow);
t1.join();
}
ClassB::TcpStatistics()
{
while (true)
{
GetAndOutputEstats(row, TcpConnectionEstatsBandwidth)
// some more code here
this_thread::sleep_for(milliseconds(1000));
}
}
b)
ClassB::ClassB()
{
MIB_TCPROW client4ConnectRow;
void* clientConnectRow = NULL;
clientConnectRow = &client4ConnectRow;
UINT winStatus = GetTcpRow(localPort, hostPort, MIB_TCP_STATE_ESTAB, (PMIB_TCPROW)clientConnectRow);
m_clientConnectRow = clientConnectRow;
TcpStatistics();
}
ClassB::TcpStatistics()
{
ToggleAllEstats(m_clientConnectRow , TRUE);
void* row = m_clientConnectRow;
GetAndOutputEstats(row, TcpConnectionEstatsBandwidth)
// some more code here
}
ClassB::GetAndOutputEstats(void* row, TCP_ESTATS_TYPE type)
{
//...
winStatus = GetPerTcpConnectionEStats((PMIB_TCPROW)row, type, NULL, 0, 0, ros, 0, rosSize, rod, 0, rodSize);
if (winStatus != NO_ERROR) {wprintf(L"\nGetPerTcpConnectionEStats %s failed. status = %d", estatsTypeNames[type], winStatus); //
}
else { ...}
}
ClassA::FunA()
{
classB_ptr->TcpStatistics();
}
I found a work around for the second part of my question. I am posting it here, in case someone else find it useful. There might be other solutions too, more advanced, but this is how I did it myself. We have to first Obtain MIB_TCPROW corresponding to the TCP connection and then to Enable Estats collection before dumping current stats. So, what I did was to add all of these in a function and call this instead, every time I want to get the stats.
void
ClassB::FunSetTcpStats()
{
MIB_TCPROW client4ConnectRow;
void* clientConnectRow = NULL;
clientConnectRow = &client4ConnectRow;
//this is for the statistics
UINT winStatus = GetTcpRow(lPort, hPort, MIB_TCP_STATE_ESTAB, (PMIB_TCPROW)clientConnectRow); //lPort & hPort in htons!
if (winStatus != ERROR_SUCCESS) {
wprintf(L"\nGetTcpRow failed on the client established connection with %d", winStatus);
return;
}
//
// Enable Estats collection and dump current stats.
//
ToggleAllEstats(clientConnectRow, TRUE);
TcpStatistics(clientConnectRow); // same as GetAllEstats() in msdn
}
I'm studying multi-thread program using Visual c++ to develop a sound signal processing program. To create basic structure of the program, I wrote a simple code having four threads that move synchronously, but they do not work well.
Specifications are as follows.
There are four threads: bg_thread, main_thread, sub_thread [0], sub_thread [1].
bg_thread triggers main_thread at regular intervals
main_thread triggers sub_thread [0] every time and triggers sub_thread [1] once every two times.
main_thread is a function in main_class
sub_thread [0], sub_thread [1] are functions in sub_class
The program is as follows:
#include "process.h"
#include "windows.h"
#include "stdio.h"
class Sub_class
{
public:
HANDLE hEvent2;
Sub_class(int no);
bool loop_ok;
bool calcstart;
int sub_class_no;
void do_sub_loop2();
};
class Main_class {
public:
bool thread_go;
bool go_flag = false;
Sub_class *sub_cls[2];
Main_class();
~Main_class();
int start_loop();
};
Main_class *main_cls = 0;
HANDLE g_bg_wait = 0;
HANDLE g_main_event = 0;
bool bg_go = true;
unsigned __stdcall start_bg_loop(void *parg)
{
WaitForSingleObject(g_bg_wait, INFINITE);
while (bg_go)
{
Sleep(100); // goto sleep for 100 milliseconds
SetEvent(g_main_event);
}
return 0;
}
unsigned __stdcall start_main_loop(void *parg)
{
main_cls->start_loop();
return 0;
}
//---------------------------------------------------------------------------------
int main()
{
main_cls = new Main_class();
HANDLE hEvent = 0;
HANDLE hndl = 0;
hEvent = CreateEvent(NULL, TRUE, FALSE, "bg_event");
hndl = (HANDLE)_beginthreadex(0, 0, &start_bg_loop, 0, 0, 0);
g_bg_wait = hEvent;
hEvent = CreateEvent(NULL, FALSE, FALSE, "main_event");
hndl = (HANDLE)_beginthreadex(0, 0, &start_main_loop, 0, 0, 0);
g_main_event = hEvent;
main_cls->sub_cls[0] = new Sub_class(0);
main_cls->sub_cls[1] = new Sub_class(1);
Sleep(1000);
bg_go = false;
CloseHandle(g_bg_wait);
CloseHandle(g_main_event);
}
int Main_class::start_loop()
{
Sleep(10);
SetEvent(g_bg_wait);
while (thread_go)
{
WaitForSingleObject(g_main_event, INFINITE);
printf("Trigger SubClass 0\n");
sub_cls[0]->calcstart = true;
SetEvent(sub_cls[0]->hEvent2);
if (go_flag)
{
printf("Trigger SubClass 1\n");
sub_cls[1]->calcstart = true;
SetEvent(sub_cls[1]->hEvent2);
}
else
{
sub_cls[1]->calcstart = false;
}
go_flag = !go_flag;
}
return 0;
}
Main_class::Main_class()
{
thread_go = true;
}
Main_class::~Main_class()
{
thread_go = false;
}
static unsigned __stdcall executeLauncher2(void* args) {
reinterpret_cast<Sub_class*>(args)->do_sub_loop2();
return 0;
}
Sub_class::Sub_class(int no)
{
sub_class_no = no;
loop_ok = true;
hEvent2 = CreateEvent(0, FALSE, FALSE, "event_2");
_beginthreadex(0, 0, &executeLauncher2, (void *)this, 0, 0);
}
void Sub_class::do_sub_loop2()
{
while (loop_ok)
{
WaitForSingleObject(hEvent2, INFINITE);
if (calcstart) printf("Start SubClass %d : OK\n", sub_class_no);
else printf("Start SubClass %d : NG ---\n", sub_class_no);
}
}
The result of running this program is as follows:
Trigger SubClass 0
Start SubClass 0 : OK
Trigger SubClass 0
Trigger SubClass 1
Start SubClass 1 : NG ---
Start SubClass 0 : OK
Trigger SubClass 0
Start SubClass 1 : NG ---
Trigger SubClass 0
Trigger SubClass 1
Start SubClass 0 : OK
Start SubClass 1 : OK
Trigger SubClass 0
Start SubClass 0 : OK
Trigger SubClass 0
Trigger SubClass 1
Start SubClass 1 : NG ---
Start SubClass 0 : OK
Trigger SubClass 0
Start SubClass 1 : NG ---
Trigger SubClass 0
Trigger SubClass 1
Start SubClass 1 : OK
Start SubClass 0 : OK
Trigger SubClass 0
Start SubClass 1 : NG ---
As you can see from the result, sub_thread [1] is often invoked (line of NG) even though triggering sub_thread [0].
I want to create the program so that when sub_thread [0] is triggered, sub_thread [0] is invoked and when sub_thread [1] is triggered,
sub_thread [1] is invoked, that is, I want to prevent NG lines.
Could you teach me how to fix this program, please ?
Thank you in advance.
CreateEvent(0, FALSE, FALSE, "event_2");
Here you create or open the same event, because you pass a name to the function. Even multiple instances of your program would open the same event object. If any other program had created an event with such a generic name as "event_2", you would also open that. That's certainly not what you want.
Pass NULL for the last parameter to create distinct event objects for each thread. Named events are usually only used for cross-process synchronization (in which case one uses unique names like a GUID), which you don't need here.
I do not know how to make stable timer.
Timer did should work every 4ms.
I did use normal event timer in "WndProc()", "CreateTimerQueueTimer()",own timer using "std::chrono::high_resolution_clock" and all timers are unstable. Of course I use one. Sometimes they are calculated at the appointed time or sometimes they are too slow what make my program not smooth. Operations are not complicated is add some integers.
CreateTimerQueueTimer()
if (!CreateTimerQueueTimer(&hLogicTimer, hTimerQ, (WAITORTIMERCALLBACK)Window::LogicThread, NULL, 0, 4, NULL)) return -1;
Window::LogicThread() function.
void Window::LogicThread()
{
Window::StartRender = false;
SC->CalculateActors();
Window::StartRender = true;
}
Own function timer called by new thread.
bool Window::LogicThread()
{
typedef std::chrono::high_resolution_clock Time;
auto start = Time::now();
const auto constWait = 4000000;
while (!Window::TerminaterThread)
{
std::this_thread::sleep_for(std::chrono::nanoseconds(constWait - std::chrono::duration_cast<std::chrono::nanoseconds>(Time::now() - start).count()));
start = Time::now(); //calculate operation time and sleep thread
Window::StartRender = false;
SC->CalculateActors();
Window::StartRender = true;
}
return true;
}