您的位置:首页 > 编程语言

系统编程之信号

2017-09-12 00:19 127 查看
同步与异步

同步:所有的操作按照一定的前后顺序执行,异步:所有的操作完全没有前后执行顺序

信号:

进程之间的一种异步通信机制,不能传递数据。

信号值

信号只是一个小整数。

使用命令kill+打印当前系统支持的所有信号的名称和信号值。

信号的发送

命令模式下发送:kill 命令

kill 信号值/信号名pid

组合模式发送:使用键盘组合键

ctrl+c  SIGINT

ctrl+z  SIGSTOP

ctrl+\  SIGQUIT

使用kill函数向执行的进程发送指定信号

int kill(pid_t pid,int sig);

信号处理方式的定义:

void (*signal)(int sig,void ((*func)(int)))(int);

//注册指定信号值的信号处理函数

//返回之前的信号处理函数

typedef void (*sighandler_t)(int);

sighandler_t signal(int signum,sighandler_t handler);

注意:signal函数可以重复注册某个信号的处理函数,当接收信号时,按当前实时的处理方式处理

练习:使用fork()创建一个子进程,子进程5秒之后向其父进程发送一个SIGUSR1信号,然后退出,同时父进程

3秒后向子进程后向子进程发送SIGUSR2信号,然后睡眠5秒,退出。

要求:

   1.父进程收到SIGUSR1信号之后,打印"hello child"

   2.子进程收到SIGUSR2信号之后,打印"hello parent"

 main()

  {

    pid = fork();

    //1.注册SIGUSR1信号处理函数

    sleep(3);

    //2.向子进程发送SIGUSR2信号

    sleep(5);    

  }

  else if(pid == 0)

  {

   //1.注册SIGUSR2信号处理函数

   sleep(5);

   //2.向父进程发送SIGUSR2信号

          

  }

使用信号来避免僵尸进程的产生

每一个进程在退出时,均会向其父进程发送一个SIGCHLD信号。

在SIGCHLD信号的处理函数中调用wait函数,即可避免僵尸进程的产生。

处理僵尸进程

父进程阻塞调用wait/waitpid

父进程fork子进程,子进程fork()孙进程,子进程退出,父进程wait子进程

使用信号,在SIGCHLD信号的处理函数中调用wait

总结:

    信号是一种异步的通知机制,不能携带数据;

    signal函数只能更改指定信号的处理函数,不发送信号。

    kill函数可以向任意指定的进程发送任意指定的信号。

    每一个信号的处理方式有三种(除SIGKILL信号外),SIGIGN,SIGDFL,指定函数处理。

    父进程的信号处理方式会被子进程继承。

#include <stdio.h>
#include <signal.h>
#include <unistd.h>

void sig_handler(int sig_no);

int main(int argc,char *argv[])
{
pid_t child_pid=0;
if((child_pid = fork())>0)
{
//调用sig_handler函数,并向其发送一个SIGUSR1信号
signal(SIGUSR1,sig_handler);
sleep(3);
//箱子进程发送SIGUSR信号
kill(child_pid,SIGUSR2);
sleep(5);
printf("parent process exit...\n");

}
else if(child_pid==0)
{
//调用sig_handler函数,并向其发送一个SIGUSR2信号
signal(SIGUSR2,sig_handler);//子进程相符进程发送一个SIGNAL信号
sleep(5);
//向父进程发送SIGUSR1信号
kill(getppid(),SIGUSR1);
printf("child process exit...\n");
}
else
{
}

return 0;
}

void sig_handler(int sig_no)
{
switch(sig_no)
{
case SIGUSR1:
printf("hello child...\n");
break;
case SIGUSR2:
printf("hello parent...\n");
break;
}

}


上面的程序可以看出父子进程是异步的:

       但是,线程是不是异步的,有人说创建线程的顺序决定进程结束的先后顺序,但是这并不正确,要看你在什么地方等待线程的结束,

#include <pthread.h>
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>

#define THREAD_FUNC
THREAD_FUNC void *thread_func1(void *arg);
THREAD_FUNC void *thread_func2(void *arg);
THREAD_FUNC void *thread_func3(void *arg);

typedef struct argument
{
char ch;
int count;
}argument_t;

int main(int argc,char *argv[])
{

//定义线程号
pthread_t thread_id1;
pthread_t thread_id2;
pthread_t thread_id3;

//给线程函数参数结构体开辟空间
argument_t *arg1 = (argument_t *)malloc(sizeof(argument_t));
argument_t *arg2 = (argument_t *)malloc(sizeof(argument_t));
argument_t *arg3 = (argument_t *)malloc(sizeof(argument_t));

//给arg1赋值并创建线程一
arg1->ch='a';
arg1->count=2;
pthread_create(&thread_id1,NULL,thread_func1,arg1);

//给arg2赋值并创建线程二
arg2->ch='b';
arg2->count=1;
pthread_create(&thread_id2,NULL,thread_func2,arg2);
//给arg3赋值并创建线程三
arg3->ch='c';
arg3->count=3;
pthread_create(&thread_id3,NULL,thread_func3,arg3);

//等待线程退出

if(!pthread_equal(pthread_self(),thread_id1))
pthread_join(thread_id1,NULL);

if(!pthread_equal(pthread_self(),thread_id2))
pthread_join(thread_id2,NULL);

if(!pthread_equal(pthread_self(),thread_id3))
pthread_join(thread_id3,NULL);
free(arg1);
free(arg2);
return 0;
}

THREAD_FUNC void *thread_func1(void *arg)
{
//sleep(10);
argument_t *p=(argument_t *)arg;
int i=0;
for(i=0;i<p->count;i++)
{
printf("%c",p->ch);
}
printf("\n");
//线程退出
pthread_exit(NULL);
}

THREAD_FUNC void *thread_func2(void *arg)
{
// sleep(3);
argument_t *p=(argument_t *)arg;
int i=0;
for(i=0;i<p->count;i++)
{
printf("%c",p->ch);
}
printf("\n");
//线程退出
pthread_exit(NULL);
}

THREAD_FUNC void *thread_func3(void *arg)
{
// sleep(3);
argument_t *p=(argument_t *)arg;
int i=0;
for(i=0;i<p->count;i++)
{
printf("%c",p->ch);
}
printf("\n");
//线程退出
pthread_exit(NULL);
}



我们运行这个程序3次。可以看到结果并不一致。这是因为这三个线程之间是一个异步的过程

#include <pthread.h>
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>

#define THREAD_FUNC
THREAD_FUNC void *thread_func1(void *arg);
THREAD_FUNC void *thread_func2(void *arg);
THREAD_FUNC void *thread_func3(void *arg);

typedef struct argument
{
char ch;
int count;
}argument_t;

int main(int argc,char *argv[])
{

//定义线程号
pthread_t thread_id1;
pthread_t thread_id2;
pthread_t thread_id3;

//给线程函数参数结构体开辟空间
argument_t *arg1 = (argument_t *)malloc(sizeof(argument_t));
argument_t *arg2 = (argument_t *)malloc(sizeof(argument_t));
argument_t *arg3 = (argument_t *)malloc(sizeof(argument_t));

//给arg1赋值并创建线程一
arg1->ch='a';
arg1->count=2;
pthread_create(&thread_id1,NULL,thread_func1,arg1);
//等待进程退出
if(!pthread_equal(pthread_self(),thread_id1))
pthread_join(thread_id1,NULL);

//给arg2赋值并创建线程二
arg2->ch='b';
arg2->count=1;
pthread_create(&thread_id2,NULL,thread_func2,arg2);
//等待进程的退出
if(!pthread_equal(pthread_self(),thread_id2))
pthread_join(thread_id2,NULL);

//给arg3赋值并创建线程三
arg3->ch='c';
arg3->count=3;
pthread_create(&thread_id3,NULL,thread_func3,arg3);
//等待进程的退出
if(!pthread_equal(pthread_self(),thread_id3))
pthread_join(thread_id3,NULL);

//等待线程退出

//if(!pthread_equal(pthread_self(),thread_id1))
// pthread_join(thread_id1,NULL);

//if(!pthread_equal(pthread_self(),thread_id2))
// pthread_join(thread_id2,NULL);

//if(!pthread_equal(pthread_self(),thread_id3))
// pthread_join(thread_id3,NULL);
free(arg1);
free(arg2);
return 0;
}

THREAD_FUNC void *thread_func1(void *arg)
{
//sleep(10);
argument_t *p=(argument_t *)arg;
int i=0;
for(i=0;i<p->count;i++)
{
printf("%c",p->ch);
}
printf("\n");
//线程退出
pthread_exit(NULL);
}

THREAD_FUNC void *thread_func2(void *arg)
{
// sleep(3);
argument_t *p=(argument_t *)arg;
int i=0;
for(i=0;i<p->count;i++)
{
printf("%c",p->ch);
}
printf("\n");
//线程退出
pthread_exit(NULL);
}

THREAD_FUNC void *thread_func3(void *arg)
{
// sleep(3);
argument_t *p=(argument_t *)arg;
int i=0;
for(i=0;i<p->count;i++)
{
printf("%c",p->ch);
}
printf("\n");
//线程退出
pthread_exit(NULL);
}



如果,我们把等待进程的命令放到创建进程命令的后面,这样我们就能看出只有等待一个进程结束之后,我们才能创建下一个进程。
所以,所有进程会顺序进行。

即    pthrea_ t     create();

        phread_t      join();

 
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: