alarm的响应线程是谁?

gaoteng1984 2008-09-26 10:05:53
我现在想做1个定时器,定时器回调函数里,要访问1个队列。这个队列在程序其他代码里也要访问。
我使用alarm做定时,但是不知道该队列是否需要进行互斥。
alarm到时间时,回调函数到底是由哪个线程调用的?我写了代码进行测试,结果如下:

Thread Id is :18561
Thread Id is :18561
Error!
Begin.
1111111111111111111111111111111111111111111100000000000000000000
End.

测试代码在最后,大体是先设好alarm在2秒后调Func,主程序里不断往buf[64]数组里交替写全0和全1,Func里输出当前线程ID,和buf内容
我就奇怪了,为啥相应回调函数的线程就是主线程呢,而且此时主线程显然正在忙碌运行中,是被OS强行“打断”的。
如果真是这样的话,我要在Func里访问队列,主线程里也要访问队列,那么,给队列加上互斥操作,起作用吗?这里明明是1个线程啊,不知道互斥操作还是否管用。
百思不得其解,忘高人指点~


#include <sys/types.h>
#include <linux/unistd.h>
#include <unistd.h>
#include <stdio.h>
#include <signal.h>

#define gettid() syscall(__NR_gettid)
#define LENGTH 64
int buf[LENGTH];

void Func(int sig)
{
pid_t threadId = gettid();
printf("Thread Id is :%d\n", (int)threadId);
int item = buf[0];
int i;
for(i = 0;i < LENGTH; ++i)
{
if (buf[i] != item)
{
printf("Error!\n");
break;
}
}
printf("Begin.\n");
for(i = 0; i < LENGTH; ++i)
{
printf("%d", buf[i]);
}
printf("\nEnd.\n");
}


int main()
{
pid_t threadId = gettid();
printf("Thread Id is :%d\n", (int)threadId);

signal(SIGALRM, Func);
alarm(2);

int a = 0;
while(1)
{
int i;
for(i = 0; i < LENGTH; ++i)
{
buf[i] = a;
}
a = (a + 1) & 1;
}

return 0;
}
...全文
277 10 打赏 收藏 转发到动态 举报
写回复
用AI写文章
10 条回复
切换为时间正序
请发表友善的回复…
发表回复
librangel 2008-09-30
  • 打赏
  • 举报
回复
mark
csan 2008-09-28
  • 打赏
  • 举报
回复
study!store up!

thanks~~
gaoteng1984 2008-09-28
  • 打赏
  • 举报
回复
[Quote=引用 6 楼 unilgr 的回复:]
一旦在多线程使用信号要考虑好几点:信号处理函数中
处理的可重入性;为每个线程设置正确的signal mask;普通信号是reliable,但不是realtime signal,确认你要使用的类型。
[/Quote]
谢谢您啦!我刚知道有signal mask这个东西。
我的需求不太适合用循环sleep等待,因为有可能到来新的定时请求,早于当前的定时时间,因此如果当前sleep(3),突然来了一个1秒后执行任务的请求,就没办法打断目前这个sleep了。
我最后设计的方案是,在signal SIGALRM的处理函数里,使用条件变量,即释放条件变量,而在另一个线程里,等待条件变量。来了通知以后该线程被唤醒,然后进入mutex保护的临界区去访问共享队列。
gaoteng1984 2008-09-27
  • 打赏
  • 举报
回复
[Quote=引用 4 楼 guosha 的回复:]
对共享的资源的存取要互斥,比如用锁机制,但是你在信号处理里加锁去做这个事的话,因为信号发生的异步性,就可能出现死锁。所以你把它放到信号处理里去是不行的。一般来说信号处理都是很简单的动作。
[/Quote]
我明白您的意思了,如果main里上了锁,当信号来了后,进入回调函数里又去占这个锁,因为这是同一个线程,所以就死锁了。
谢谢!
悠悠长风 2008-09-26
  • 打赏
  • 举报
回复
信号处理函数要尽量的简单,大多数的函数都是信号非安全的函数。。。

像你这些锁,printf都是非安全的。。。

最好信号处理函数,就是置一个标志。
快乐田伯光 2008-09-26
  • 打赏
  • 举报
回复
对共享的资源的存取要互斥,比如用锁机制,但是你在信号处理里加锁去做这个事的话,因为信号发生的异步性,就可能出现死锁。所以你把它放到信号处理里去是不行的。一般来说信号处理都是很简单的动作。

[Quote=引用 3 楼 gaoteng1984 的回复:]
或者说,我不应该采用alarm,而应该采用其他定时机制,来达到对该队列的安全访问?
[/Quote]
gaoteng1984 2008-09-26
  • 打赏
  • 举报
回复
或者说,我不应该采用alarm,而应该采用其他定时机制,来达到对该队列的安全访问?
gaoteng1984 2008-09-26
  • 打赏
  • 举报
回复
[Quote=引用 1 楼 guosha 的回复:]
CPU的调度,信号的处理过程你还不是很了解的样,

你这里明明就是一个单线程进程啊,这样当信号到了时,你的进程里的执行序列就被打断了,改而去执行你的信号处理程序,等你信号处理程序处理完了,才会回去你的主进程的执行序列里去执行
[/Quote]
从测试结果看,应该是这样。
那我的共享队列访问,应该如何互斥呢?比如我在main函数里要不停的访问该队列,在回调函数Func里又要访问该队列。那么也许就会破坏这个队列了。
例如,我在main里调front函数取一个元素,刚进入front,判断完队列非空,还没来得及取数据,就被打断,去执行Func,在Func里pop了所有的元素,再return回到中断点时,在front函数里,取到的就是一个“不合法”的值。

alarm的设计者,没有考虑这种中断后发生不一致的情况吗?
快乐田伯光 2008-09-26
  • 打赏
  • 举报
回复
CPU的调度,信号的处理过程你还不是很了解的样,

你这里明明就是一个单线程进程啊,这样当信号到了时,你的进程里的执行序列就被打断了,改而去执行你的信号处理程序,等你信号处理程序处理完了,才会回去你的主进程的执行序列里去执行
unilgr 2008-09-26
  • 打赏
  • 举报
回复
信号处理函数中,不要用不可重入的函数,比如libc标准IO函数,malloc/free等,POSIX指定了异步信号安全的函数列表。
首先,先划分好功能的实现方法,定时完全有一个线程来做。所有线程都有共享signal action,但是都有独立的signal mask,除了使用定时器的线程外,让其它线程阻塞SIGALRM
其次,更实时的定时器控制用
#include <sys/time.h>

int getitimer(int which, struct itimerval *value);
int setitimer(int which, const struct itimerval *restrict value,
struct itimerval *restrict ovalue);
POSIX:XSI
最后,我觉得像你这种需求,用普通的循环计时即简单又不易出错,gettimeofday。一旦在多线程使用信号要考虑好几点:信号处理函数中
处理的可重入性;为每个线程设置正确的signal mask;普通信号是reliable,但不是realtime signal,确认你要使用的类型。


23,223

社区成员

发帖
与我相关
我的任务
社区描述
Linux/Unix社区 应用程序开发区
社区管理员
  • 应用程序开发区社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧