In case of one-shot timer i can use semaphore to wait for timer callback completion. But if timer was fired several times it doesn't help. Consider the following code:
在单次定时器的情况下,我可以使用信号量来等待定时器回调完成。但是如果计时器被多次触发它没有帮助。请考虑以下代码:
#include <stdlib.h>
#include <stdint.h>
#include <stdio.h>
#include <signal.h>
#include <time.h>
#include <unistd.h>
#include <pthread.h>
#define N 10
void timer_threaded_function(sigval_t si)
{
uint8_t *shared_resource = si.sival_ptr;
sleep(rand() % 7);
/* ... manipulate with shared_resource */
return;
}
int main()
{
struct sigevent sig_ev = {0};
uint8_t *shared_resource = malloc(123);
timer_t timer_id;
int i;
sig_ev.sigev_notify = SIGEV_THREAD;
sig_ev.sigev_value.sival_ptr = shared_resource;
sig_ev.sigev_notify_function = timer_threaded_function;
sig_ev.sigev_notify_attributes = NULL;
timer_create(CLOCK_REALTIME, &sig_ev, &timer_id);
for (i = 0; i < N; i++) {
/* arm timer for 1 nanosecond */
timer_settime(timer_id, 0,
&(struct itimerspec){{0,0},{0,1}}, NULL);
/* sleep a little bit, so timer will be fired */
usleep(1);
}
/* only disarms timer, but timer callbacks still can be running */
timer_delete(timer_id);
/*
* TODO: safe wait for all callbacks to end, so shared resource
* can be freed without races.
*/
...
free(shared_resource);
return 0;
}
timer_delete() only disarms timer (if it is was armed) and frees assocoated with timer resources. But timer callbacks still can be running. So we cannot free shared_resource, otherwise race condition may occur. Is there any method to cope with this situation?
timer_delete()仅解除计时器(如果它已设防)并释放与计时器资源相关联的计时器。但是计时器回调仍然可以运行。所以我们不能释放shared_resource,否则可能会出现竞争条件。有没有办法应对这种情况?
I thougth about reference counting, but it doesn't help, because we doesn't know how much threads actually will try to access shared resource (cause of timer overruns).
我对引用计数感兴趣,但它没有帮助,因为我们不知道实际上有多少线程会尝试访问共享资源(导致计时器溢出)。
1 个解决方案
#1
1
It is thoroughly unsatisfactory :-(. I have looked, and there does not seem to be any way to discover whether the sigevent (a) has not been fired, or (b) is pending, or (c) is running, or (d) has completed.
完全不能令人满意:-(。我看过了,似乎没有任何方法可以发现sigevent(a)是否未被解雇,或者(b)是否正在等待,或者(c)是否正在运行,或者( d)已经完成。
Best I can suggest is an extra level of indirection, and a static to point at the shared resource. So:
我可以建议的最好是间接的额外级别,以及共享资源的静态指向。所以:
static foo_t* p_shared ;
....
p_shared = shared_resourse ;
.....
sig_ev.sigev_value.sival_ptr = &p_shared ;
where foo_t
is the type of the shared resource.
其中foo_t是共享资源的类型。
Now we can use some atomics... in timer_threaded_function()
:
现在我们可以在timer_threaded_function()中使用一些原子...
foo_t** pp_shared ;
foo_t* p_locked ;
foo_t* p_shared ;
pp_shared = so.sival_ptr ;
p_locked = (void*)UINPTR_MAX ;
p_shared = atomic_swap(pp_shared, p_locked) ;
if (p_shared == p_locked)
return ; // locked already.
if (p_shared == NULL)
return ; // destroyed already.
.... proceed to do the usual work ...
if (atomic_cmp_swap(pp_shared, &p_locked, p_shared))
return ; // was locked and is now restored
assert(p_locked == NULL) ;
... the shared resource needs to be freed ...
And in the controlling thread:
并在控制线程中:
timer_delete(timer_id) ; // no more events, thank you
p_s = atomic_swap(&p_shared, NULL) ; // stop processing events
if (p_s == (void*)UINTPTR_MAX)
// an event is being processed.
if (p_s != NULL)
... the shared resource needs to be freed ...
When the event thread finds that the shared resourse needs to be freed, it can do it itself, or signal to the controlling thread that the event has been processed, so that the controlling thread can go ahead and do the free. That's largely a matter of taste.
当事件线程发现需要释放共享资源时,它可以自己执行,或者向控制线程发信号通知事件已被处理,以便控制线程可以继续执行并*执行。这主要是品味问题。
Basically, this is using atomics to provide a sort of a lock, whose value is tri-state: NULL <=> destroyed ; UINTPTR_MAX <=> locked ; anything else <=> unlocked.
基本上,这是使用atomics提供一种锁,其值为三态:NULL <=>被破坏; UINTPTR_MAX <=>已锁定;其他任何东西<=>解锁。
The down-side is the static p_shared
, which has to remain in existence until the timer_threaded_function()
has finished and will never be called again... and since those are precisely the things that are unknowable, static p_shared
is, effectively, a fixture :-(.
下边是静态p_shared,它必须保持存在直到timer_threaded_function()完成并且永远不会再被调用...并且由于那些正是不可知的东西,静态p_shared实际上是一个夹具:-(。
#1
1
It is thoroughly unsatisfactory :-(. I have looked, and there does not seem to be any way to discover whether the sigevent (a) has not been fired, or (b) is pending, or (c) is running, or (d) has completed.
完全不能令人满意:-(。我看过了,似乎没有任何方法可以发现sigevent(a)是否未被解雇,或者(b)是否正在等待,或者(c)是否正在运行,或者( d)已经完成。
Best I can suggest is an extra level of indirection, and a static to point at the shared resource. So:
我可以建议的最好是间接的额外级别,以及共享资源的静态指向。所以:
static foo_t* p_shared ;
....
p_shared = shared_resourse ;
.....
sig_ev.sigev_value.sival_ptr = &p_shared ;
where foo_t
is the type of the shared resource.
其中foo_t是共享资源的类型。
Now we can use some atomics... in timer_threaded_function()
:
现在我们可以在timer_threaded_function()中使用一些原子...
foo_t** pp_shared ;
foo_t* p_locked ;
foo_t* p_shared ;
pp_shared = so.sival_ptr ;
p_locked = (void*)UINPTR_MAX ;
p_shared = atomic_swap(pp_shared, p_locked) ;
if (p_shared == p_locked)
return ; // locked already.
if (p_shared == NULL)
return ; // destroyed already.
.... proceed to do the usual work ...
if (atomic_cmp_swap(pp_shared, &p_locked, p_shared))
return ; // was locked and is now restored
assert(p_locked == NULL) ;
... the shared resource needs to be freed ...
And in the controlling thread:
并在控制线程中:
timer_delete(timer_id) ; // no more events, thank you
p_s = atomic_swap(&p_shared, NULL) ; // stop processing events
if (p_s == (void*)UINTPTR_MAX)
// an event is being processed.
if (p_s != NULL)
... the shared resource needs to be freed ...
When the event thread finds that the shared resourse needs to be freed, it can do it itself, or signal to the controlling thread that the event has been processed, so that the controlling thread can go ahead and do the free. That's largely a matter of taste.
当事件线程发现需要释放共享资源时,它可以自己执行,或者向控制线程发信号通知事件已被处理,以便控制线程可以继续执行并*执行。这主要是品味问题。
Basically, this is using atomics to provide a sort of a lock, whose value is tri-state: NULL <=> destroyed ; UINTPTR_MAX <=> locked ; anything else <=> unlocked.
基本上,这是使用atomics提供一种锁,其值为三态:NULL <=>被破坏; UINTPTR_MAX <=>已锁定;其他任何东西<=>解锁。
The down-side is the static p_shared
, which has to remain in existence until the timer_threaded_function()
has finished and will never be called again... and since those are precisely the things that are unknowable, static p_shared
is, effectively, a fixture :-(.
下边是静态p_shared,它必须保持存在直到timer_threaded_function()完成并且永远不会再被调用...并且由于那些正是不可知的东西,静态p_shared实际上是一个夹具:-(。