系统编程之信号
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 <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();
同步:所有的操作按照一定的前后顺序执行,异步:所有的操作完全没有前后执行顺序
信号:
进程之间的一种异步通信机制,不能传递数据。
信号值
信号只是一个小整数。
使用命令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();
相关文章推荐
- linux网络编程之慢系统调用被信号中断产生EINTR错误怎么解决总结
- Linux系统编程4.信号处理
- PHP系统编程--03.PHP进程信号处理
- Linux系统编程——进程间通信:信号中断处理
- linux系统编程之信号(三):信号的阻塞与未决
- linux系统编程之信号 test10_10.c
- 系统编程--信号
- linux系统编程之信号(六):信号发送函数sigqueue和信号安装函数sigaction
- linux系统编程之信号(二)
- linux系统编程之信号(三)
- 十七、Linux系统编程-信号(四)信号在内核中表示、信号的阻塞和未决
- Linux系统编程--信号及信号处理(一)
- linux系统编程之信号:信号发送函数sigqueue和信号安装函数sigaction
- linux系统编程之信号(一):中断与信号
- bash脚本编程之十四 信号捕捉及系统管理之任务计划
- linux系统编程之信号(一)
- 利用c语言编程在stm32上输出信号控制电压放大与滤波系统和显示功能
- 系统编程-信号?
- linux 系统编程 之信号 test10_1.c
- linux系统编程之信号(八):三种时间结构及定时器setitimer()详解