您的位置:首页 > 运维架构 > Linux

linux线程同步03

2016-04-07 10:42 387 查看
信号是向进程发送的软件通知,通知进程有事件发生。引发信号的事件发生时,信号就被生成了。进程根据信号采取行动时,信号就被传递了。信号的寿命就是信号的生成和传递之间的时间间隔。已经生成但还未被传递的信号被称为挂起的信号。在信号生成和信号传递之间可能会有相当长的时间。

signal(参数1,参数2);

参数1:我们要进行处理的信号。系统的信号我们可以再终端键入 kill -l查看(共64个)。其实这些信号时系统定义的宏。

参数2:我们处理的方式(是系统默认还是忽略还是捕获)。

一般有3中方式进行操作。

(1)eg: signal(SIGINT ,SIG_ING );

//SIG_ING 代表忽略SIGINT信号,SIGINT信号代表由InterruptKey产生,通常是CTRL
+C 或者是DELETE 。发送给所有ForeGround Group的进程。

(2)eg: signal(SIGINT ,SIG_DFL );

//SIGINT信号代表由InterruptKey产生,通常是CTRL +C或者是DELETE。发送给所有ForeGroundGroup的进程。
SIG_DFL代表执行系统默认操作,其实对于大多数信号的系统默认动作时终止该进程。这与不写此处理函数是一样的。

(3)typedef void (*sighandler_t)(int);

         sighandler_t signal(int signum, sighandler_t handler);
void SignHandler(int iSignNo)
{
printf("Capture sign no:%d/n",iSignNo);
}
<strong><span style="color:#FF0000;">
正常编译的时候不会出现恢复信号默认处理行为,默认编译,signal()调用就是POSIX行为,等同于调用sigaction,会阻塞,没有disposition.
如果编译时加了额外的选项例如-std=c99,那么就是SysV的行为,调用内核的signal。</span></strong>


在signal处理机制下,还有许多特殊情况需要考虑:

1、  注册一个信号处理函数,并且处理完毕一个信号之后,是否需要重新注册,才能够捕捉下一个信号;

2、  如果信号处理函数正在处理信号,并且还没有处理完毕时,又发生了一个同类型的信号,这时该怎么处理;

3、  如果信号处理函数正在处理信号,并且还没有处理完毕时,又发生了一个不同类型的信号,这时该怎么处理;

4、  如果程序阻塞在一个系统调用(如read(...))时,发生了一个信号,这时是让系统调用返回错误再接着进入信号处理函数,还是先跳转到信号处理函数,等信号处理完毕后,系统调用再返回。

 

#include <signal.h>

int sigaction(int signum, const struct sigaction *act, struct sigaction *oldact);

sigaction也用于注册一个信号处理函数。

参数signum为需要捕捉的信号;

参数 act是一个结构体,里面包含信号处理函数地址、处理方式等信息。

参数oldact是一个传出参数,sigaction函数调用成功后,oldact里面包含以前对signum的处理方式的信息。

如果函数调用成功,将返回0,否则返回-1

----------------------------------我是分割线---------------------------------------------
在Linux的多线程中使用信号机制,与在进程中使用信号机制有着根本的区别,可以说是完全不同。在进程环境中,对信号的处理是,先注册信号处理函数,当信号异步发生时,调用处理函数来处理信号。它完全是异步的(我们完全不知到信号会在进程的那个执行点到来!)。然而信号处理函数的实现,有着许多的限制;比如有一些函数不能在信号处理函数中调用;再比如一些函数read、recv等调用时会被异步的信号给中断(interrupt),因此我们必须对在这些函数在调用时因为信号而中断的情况进行处理(判断函数返回时
enno 是否等于 EINTR)。

但是在多线程中处理信号的原则却完全不同,它的基本原则是:将对信号的异步处理,转换成同步处理,也就是说用一个线程专门的来“同步等待”信号的到来,而其它的线程可以完全不被该信号中断/打断(interrupt)。这样就在相当程度上简化了在多线程环境中对信号的处理。而且可以保证其它的线程不受信号的影响。这样我们对信号就可以完全预测,因为它不再是异步的,而是同步的(我们完全知道信号会在哪个线程中的哪个执行点到来而被处理!)。而同步的编程模式总是比异步的编程模式简单。其实多线程相比于多进程的其中一个优点就是:多线程可以将进程中异步的东西转换成同步的来处理。

所谓的同步就是 一直阻塞等待,直到屏蔽集合中的信号到来。

1.1  sigwait
      sigwait的含义就如同它的字面意思:等待某个信号的到来。如果调用该函数的线程没有等到它想等待的信号那么该线程就休眠。
      要达到等到一个信号,我们得做下面的事!
      首先,定义一个信号集
#include <signal.h>sigset_t set;
       其次,向信号集中加入我们想等待的信号

#include <signal.h>
int sigemptyset(sigset_t *set);//清空信号集int sigaddset(sigset_t *set,int signo);//将某个信号加入到信号集中int sigdelset(sigset_t *set,int signo);//删除信号集中的某个信号int sigfillset(sigset_t *set);//包含所有已定义的信号
     最后,将该信号集中的信号加入到线程信号屏蔽字(线程信号等待队列)中

#include <signal.h>
int pthread_sigmask(int how, const sigset_t *set, sigset_t *oldset);
how:

      SIG_BLOCK:把参数set中的信号添加到线程的信号屏蔽字中
      SIG_SETMASK:把线程的信号屏蔽字设置为参数set中的信号
      SIG_UNBLOCK:从线程信号屏蔽字中删除参数set中的信号
set:用户设置的信号屏蔽字
oldset:返回原先的信号屏蔽字
     
     经过这样的设置我们就可以在线程该等待的地方调用sigwait休眠该线程了。
1.2  pthread_kill

#include <signal.h>
int pthread_kill(pthread_t thread, int sig);
thread:给哪个线程发送信号

sig:发送的信号值

2
程序示例
#include <stdio.h>
#include <pthread.h>
#include <signal.h>
void *threadfunc1(void *pvoid)
{
int signum;
sigset_t sig;
int signum;
sigemptyset(&sig);
sigaddset(&sig,SIGUSR1);
pthread_sigmask(SIG_BLOCK,&sig,NULL);//设置该线程的信号屏蔽字为SIGUSR1
while(1)
{
sigwait(&sig,&signum);//睡眠等待SIGUSR1信号的到来 printf("threadfunc1 waiting is over!\n");
}
}

void *threadfunc2(void *pvoid)
{
int signum;
sigset_t sig;
int signum;
sigemptyset(&sig);
sigaddset(&sig,SIGUSR1);
pthread_sigmask(SIG_BLOCK,&sig,NULL);//设置该线程的信号屏蔽字为SIGUSR1
while(1)
{
sigwait(&sig,&signum);//睡眠等待SIGUSR1信号的到来
printf("threadfunc2 waiting is over!\n");
}
}
void main()
{
pthread_t thread1,thread2;
pthread_create(&thread1,NULL,threadfunc1,(void *)NULL);
pthread_create(&thread2,NULL,threadfunc2,(void *)NULL);

pthread_detach(thread1);
pthread_detach(thread2);

struct sigaction act;
act.sa_handler=SIG_IGN;
sigemptyset(&act.sa_mask);
act.sa_flags=0;
sigaction(SIGUSR1,&act,0);//设置信号SIGUSR1的处理方式忽略   while(1)
{
printf("please input select a number in (1,2)!\n");
scanf("%d",&i);
if(i==1)
pthread_kill(thread1,SIGUSR1); if(i==2)
pthread_kill(thread2,SIGUSR1);
}
}//编译 gcc -o pthread pthread.c -lpthread
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: