在单次定时器的情况下,我可以使用信号量来等待定时器回调完成。 但是如果计时器被多次触发它并没有帮助。请考虑以下代码:
#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()仅解除计时器(如果已设防)并释放与计时器资源相关联的计时器。但是计时器回调仍然可以运行。所以我们不能释放shared_resource,否则可能会出现竞争条件。有没有办法来应对这种情况?
我对引用计数感兴趣,但它没有帮助,因为我们不知道实际上有多少线程会尝试访问共享资源(导致计时器溢出)。
答案 0 :(得分:1)
完全不能令人满意:-(。我看了,似乎没有任何方法可以发现sigevent(a)是否未被解雇,或者(b)是否正在等待,或者(c)是否正在运行,或(d)已完成。
我能建议的最好是间接的额外级别,以及共享资源的静态指向。所以:
static foo_t* p_shared ;
....
p_shared = shared_resourse ;
.....
sig_ev.sigev_value.sival_ptr = &p_shared ;
其中foo_t
是共享资源的类型。
现在我们可以在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 ...
在控制线程中:
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 ...
当事件线程发现需要释放共享资源时,它可以自己执行,或者向控制线程发信号通知事件已被处理,以便控制线程可以继续执行并自由执行。这主要是品味问题。
基本上,这是使用atomics来提供一种锁,其值为三态:NULL&lt; =&gt;被毁UINTPTR_MAX&lt; =&gt;锁定其他任何&lt; =&gt;解锁。
向下是static p_shared
,它必须保持存在直到timer_threaded_function()
完成并且永远不会被再次调用......并且因为那些正是不可知的事物, static p_shared
实际上是一个固定装置: - (。