问题:
1.exit(状态码)返回状态码有什么意义?
返回值被系统得到。系统根据状态码进行日志记录
返回值被调用者得到:system/wait.程序会根据返回状态码进程对应处理。
exit(状态码) = main函数中的return状态码;
2.状态码的第二个字节才是exit()的返回值或者return值
WEXITSTATUS(status),取出第二个字节
一、进程的基本控制
1.进程的常见控制函数
1.1 为什么需要控制进程?
1.2 pause/sleep/usleep
1.3 atexit on_exit
#include <stdlib.h>
int atexit(void (*function)(void));
#include <stdlib.h>
int on_exit(void (*function)(int , void *), void *arg);
#include <stdio.h>
#include <stdlib.h>
void fun()
{
printf("hello fun\n");
}
main()
{
atexit(fun);
printf("hello main\n");
}
在进程退出之前,会回调function函数
on_exit的function带参数的
2.进程与文件锁
2.1 在多进程下文件读写是共享的
问题:
怎么知道一个文件正在被另外进程读写?
解决方案:
文件锁(一般是建议锁)
API:
fcntl (文件锁受内核参数影响:强制锁,建议锁)
编程技巧:
对一个文件加锁
判定一个文件是否存在锁(只要加一把锁,需要判定)
函数说明:
#include <unistd.h>
#include <fcntl.h>
int fcntl(int fd, int cmd, ... /* arg */ );
返回值:
0:加锁成功
-1:加锁失败
参数:
fd:被加锁的文件描述符号
cmd:锁的操作方式:F_SETLK(已经加锁,异常返回) F_UNLK F_SETLKW
struct flock *lk:锁的描述
l_type Type of blocking lock found.
l_whence
SEEK_SET.
l_start
Start of the blocking lock.
l_len Length of the blocking lock.
l_pid Process ID of the process that holds the blocking lock.
案例:
1、过程:
打开一个文件
描述锁
加锁
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
main()
{
int fd = 0;
struct flock lk = {0};
int r = 0;
fd = open("a.txt",O_RDWR);
if(fd == -1) printf(":%m\n"),exit(-1);
r = fcntl(fd,F_GETLK,&lk);
if(r == 0) printf("get lock success!\n ");
if(lk.l_type == F_WRLCK) printf("write lock\n ");
printf("start:%d, len:%d\n ",lk.l_start,lk.l_len);
printf("pid:%d\n ",lk.l_pid);
while(1);
}
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
main()
{
int fd;
struct flock lk;
int r;
fd = open("a.txt",O_RDWR);
if(fd == -1) printf(":%m\n"),exit(-1);
lk.l_type = F_WRLCK;
lk.l_whence = SEEK_SET;
lk.l_start = 5;
lk.l_len = 10;
r = fcntl(fd,F_SETLK,&lk);
if(r == 0) printf("Add lock success!\n ");
else printf("Add lock failed!\n ");
while(1);
}
锁也是一个进程可以共享的信息
二、信号
1.信号的作用
进程之间通信比较麻烦
但进程之间又必须通信,比如父子进程之间
作用:通知其他进程响应。进程之间通信机制。
信号:接收信号的进程会马上停止,去执行信号的处理函数
默认处理函数:打印信号信息,退出
用户处理函数:自己的程序
中断:软中断
案例:
1.进程之中,默认信号处理
2.进程之中,用户处理函数
kill -s 信号 进程ID
kill -信号 进程ID
信号:数字1-31 34-64
宏:SIGINT=2
kill -l 查看所有的信号
ctrl-C就是信号2 SIGINT
信号SIGKILL SIGSTOP不能被处理
2.信号发送与安装
kill函数
#include <sys/types.h>
#include <signal.h>
int kill(pid_t pid, int sig);
正确:返回0;错误:返回-1
进程ID:
>0:发送信号到指定进程
=0:发送信号到该进程所在进程组的所有进程
=-1:发送给所有进程,除init进程外
<0:发送给指定的进程组(组ID=进程值)
3.信号的应用
3.1延时器
SIGALRM
信号发出函数:alarm
3.2定时器
int settimer(
int which;//计时方式 ITIMER_REAL ITIMER_VIRTUAL ITIMER_PROF
const struct itimerval *val;//定时器参数
struct itimer *oldval;//返回原来设置的时间,如果为NULL ,则不返回
)
struct itimerval
{
struct timeval it_interval;//间隔时间
struct timeval it_value//延时时间
}
struct timeval
{
long tv_sec;
long tv_usec;
}
#include <stdio.h>
#include <unistd.h>
#include <signal.h>
#include <sys/time.h>
void deal()
{
printf("alarm\n");
}
main()
{
struct itimerval v = {0};
signal(SIGALRM,deal);
v.it_value.tv_sec = 5;
v.it_interval.tv_sec = 1;
setitimer(ITIMER_REAL,&v,0);
//alarm(5);
while(1);
}
信号应用:
系统与应用程序之间
应用于应用程序之间
父子进程之间
案例:
demo1;
使用定时器,实现多任务切换
实现:
实现七位随机数
使用中断实现时间的显示
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <curses.h>
#include <math.h>
#include <signal.h>
#include <time.h>
#include <sys/time.h>
WINDOW *wtime,*wnumb;
int i = 0;
void showtime(int s)
{
time_t tt;
struct tm *t;
if(SIGALRM == s)
{
tt = time(0);
t = localtime(&tt);
mvwprintw(wtime,1,1,"%02d:%02d:%02d",t->tm_hour,t->tm_min,t->tm_sec);
refresh();
wrefresh(wtime);
wrefresh(wnumb);
}
}
main()
{
int num = 0;
struct itimerval timeVal = {0};
initscr();
curs_set(0);
noecho();
signal(SIGALRM,showtime);
timeVal.it_value.tv_sec = 0;
timeVal.it_value.tv_usec = 1;
timeVal.it_interval.tv_sec = 1;
setitimer(ITIMER_REAL,&timeVal,0);
wnumb = derwin(stdscr,3,11,(LINES-3)/2,(COLS-11)/2);
wtime = derwin(stdscr,3,10,0,COLS-10);
box(wnumb,0,0);
box(wtime,0,0);
while(1)
{
num = 0;
for(i=0;i<7;i++)
{
num = num*10+rand()%10;
}
mvwprintw(wnumb,1,2,"%07d",num);
refresh();
wrefresh(wnumb);
wrefresh(wtime);
usleep(500000);
}
endwin();
}
demo2:
使用两个进程实现信号的传递
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include <curses.h>
#include <math.h>
WINDOW *w;
int num = 0;
int isstop = 0;
void deal(int s)
{
isstop = (s==SIGUSR1) ? 1 : 0;
}
main()
{
int i = 0;
initscr();
curs_set(0);
noecho();
keypad(stdscr,TRUE);
keypad(w,TRUE);
w = derwin(stdscr,3,11,(LINES-3)/2,(COLS-11)/2);
box(w,0,0);
refresh();
wrefresh(w);
if(fork())
{
signal(SIGUSR1,deal);
while(1)
{
if(isstop == 1)
{
pause();
isstop = 0;
}
num = 0 ;
for(i=0;i<7;i++)
{
num = num*10 + rand()%10;
}
mvwprintw(w,1,2,"%07d",num);
refresh();
wrefresh(w);
usleep(100000);
}
}
else
{
while(1)
{
getch();
kill(getppid(),SIGUSR1);
}
}
endwin();
}
4.信号的可靠与不可靠以及信号的含义
信号有丢失(信号压缩)
由于历史的缘故:信号有压缩的需求
可靠信号与不可靠信号
早期信号1-31 31个信号,不可靠(与系统有关)
后期信号34-64 可靠信号(用户信号)
5.信号的操作
信号导致的问题
1.信号屏蔽
int sigprocmask(int how,//操作方式 SIG_BLOCK SIG_UNBLOCK SIG_SETMASK
const sigset_t*sigs,//操作的信号集合
sigset_t *oldsigs//返回原来操作的信号
);
1.1.声明一个信号集合
sigset_t sigs;
1.2.加入屏蔽信号
一组信号集合维护函数:
1.2.1.清空集合sigemptyset
1.2.2.添加信号到集合sigaddset
1.2.3.从集合删除信号sigdelset
1.2.4.添加所有信号到集合sigfillset
1.2.5.判定某个集合是否在其中sigismember
sigmask.c
#include <stdio.h>
#include <signal.h>
main()
{
int i = 0;
sigset_t sigs;
sigemptyset(&sigs);
sigaddset(&sigs,SIGINT);
sigprocmask(SIG_BLOCK,&sigs,0);
for(i=0;i<10;i++)
{
printf("%d\n",i);
sleep(1);
}
printf("i=%d\n",i);
sigprocmask(SIG_UNBLOCK,&sigs,0);
printf("over\n");
}
这个程序可以屏蔽ctrl+C
1.3.屏蔽信号
1.4.接触屏蔽
2.信号屏蔽的切换
int sigsuspend(sigset_t *sigs);
屏蔽新的信号,原来的信号失效
sigsuspend是阻塞函数,对参数信号屏蔽
对参数没有指定的信号不屏蔽,但当没有屏蔽的信号处理函数结束后返回
sigsuspend返回条件:
1、非屏蔽信号发生
2、该信号触发且有处理函数,且处理函数返回
作用:使原来屏蔽信号无效,开放原来的信号,使新的信号屏蔽,当某个信号处理函数处理完毕,sigsuspend恢复原来屏蔽信号,返回
3.查询被屏蔽的信号
sigpending(sigset_t *sig);
6.信号与进程间数据传递
sigqueue=kill
sigaction=signal
1.exit(状态码)返回状态码有什么意义?
返回值被系统得到。系统根据状态码进行日志记录
返回值被调用者得到:system/wait.程序会根据返回状态码进程对应处理。
exit(状态码) = main函数中的return状态码;
2.状态码的第二个字节才是exit()的返回值或者return值
WEXITSTATUS(status),取出第二个字节
一、进程的基本控制
1.进程的常见控制函数
1.1 为什么需要控制进程?
1.2 pause/sleep/usleep
1.3 atexit on_exit
#include <stdlib.h>
int atexit(void (*function)(void));
#include <stdlib.h>
int on_exit(void (*function)(int , void *), void *arg);
#include <stdio.h>
#include <stdlib.h>
void fun()
{
printf("hello fun\n");
}
main()
{
atexit(fun);
printf("hello main\n");
}
在进程退出之前,会回调function函数
on_exit的function带参数的
2.进程与文件锁
2.1 在多进程下文件读写是共享的
问题:
怎么知道一个文件正在被另外进程读写?
解决方案:
文件锁(一般是建议锁)
API:
fcntl (文件锁受内核参数影响:强制锁,建议锁)
编程技巧:
对一个文件加锁
判定一个文件是否存在锁(只要加一把锁,需要判定)
函数说明:
#include <unistd.h>
#include <fcntl.h>
int fcntl(int fd, int cmd, ... /* arg */ );
返回值:
0:加锁成功
-1:加锁失败
参数:
fd:被加锁的文件描述符号
cmd:锁的操作方式:F_SETLK(已经加锁,异常返回) F_UNLK F_SETLKW
struct flock *lk:锁的描述
l_type Type of blocking lock found.
l_whence
SEEK_SET.
l_start
Start of the blocking lock.
l_len Length of the blocking lock.
l_pid Process ID of the process that holds the blocking lock.
案例:
1、过程:
打开一个文件
描述锁
加锁
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
main()
{
int fd = 0;
struct flock lk = {0};
int r = 0;
fd = open("a.txt",O_RDWR);
if(fd == -1) printf(":%m\n"),exit(-1);
r = fcntl(fd,F_GETLK,&lk);
if(r == 0) printf("get lock success!\n ");
if(lk.l_type == F_WRLCK) printf("write lock\n ");
printf("start:%d, len:%d\n ",lk.l_start,lk.l_len);
printf("pid:%d\n ",lk.l_pid);
while(1);
}
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
main()
{
int fd;
struct flock lk;
int r;
fd = open("a.txt",O_RDWR);
if(fd == -1) printf(":%m\n"),exit(-1);
lk.l_type = F_WRLCK;
lk.l_whence = SEEK_SET;
lk.l_start = 5;
lk.l_len = 10;
r = fcntl(fd,F_SETLK,&lk);
if(r == 0) printf("Add lock success!\n ");
else printf("Add lock failed!\n ");
while(1);
}
锁也是一个进程可以共享的信息
二、信号
1.信号的作用
进程之间通信比较麻烦
但进程之间又必须通信,比如父子进程之间
作用:通知其他进程响应。进程之间通信机制。
信号:接收信号的进程会马上停止,去执行信号的处理函数
默认处理函数:打印信号信息,退出
用户处理函数:自己的程序
中断:软中断
案例:
1.进程之中,默认信号处理
2.进程之中,用户处理函数
kill -s 信号 进程ID
kill -信号 进程ID
信号:数字1-31 34-64
宏:SIGINT=2
kill -l 查看所有的信号
ctrl-C就是信号2 SIGINT
信号SIGKILL SIGSTOP不能被处理
2.信号发送与安装
kill函数
#include <sys/types.h>
#include <signal.h>
int kill(pid_t pid, int sig);
正确:返回0;错误:返回-1
进程ID:
>0:发送信号到指定进程
=0:发送信号到该进程所在进程组的所有进程
=-1:发送给所有进程,除init进程外
<0:发送给指定的进程组(组ID=进程值)
3.信号的应用
3.1延时器
SIGALRM
信号发出函数:alarm
3.2定时器
int settimer(
int which;//计时方式 ITIMER_REAL ITIMER_VIRTUAL ITIMER_PROF
const struct itimerval *val;//定时器参数
struct itimer *oldval;//返回原来设置的时间,如果为NULL ,则不返回
)
struct itimerval
{
struct timeval it_interval;//间隔时间
struct timeval it_value//延时时间
}
struct timeval
{
long tv_sec;
long tv_usec;
}
#include <stdio.h>
#include <unistd.h>
#include <signal.h>
#include <sys/time.h>
void deal()
{
printf("alarm\n");
}
main()
{
struct itimerval v = {0};
signal(SIGALRM,deal);
v.it_value.tv_sec = 5;
v.it_interval.tv_sec = 1;
setitimer(ITIMER_REAL,&v,0);
//alarm(5);
while(1);
}
信号应用:
系统与应用程序之间
应用于应用程序之间
父子进程之间
案例:
demo1;
使用定时器,实现多任务切换
实现:
实现七位随机数
使用中断实现时间的显示
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <curses.h>
#include <math.h>
#include <signal.h>
#include <time.h>
#include <sys/time.h>
WINDOW *wtime,*wnumb;
int i = 0;
void showtime(int s)
{
time_t tt;
struct tm *t;
if(SIGALRM == s)
{
tt = time(0);
t = localtime(&tt);
mvwprintw(wtime,1,1,"%02d:%02d:%02d",t->tm_hour,t->tm_min,t->tm_sec);
refresh();
wrefresh(wtime);
wrefresh(wnumb);
}
}
main()
{
int num = 0;
struct itimerval timeVal = {0};
initscr();
curs_set(0);
noecho();
signal(SIGALRM,showtime);
timeVal.it_value.tv_sec = 0;
timeVal.it_value.tv_usec = 1;
timeVal.it_interval.tv_sec = 1;
setitimer(ITIMER_REAL,&timeVal,0);
wnumb = derwin(stdscr,3,11,(LINES-3)/2,(COLS-11)/2);
wtime = derwin(stdscr,3,10,0,COLS-10);
box(wnumb,0,0);
box(wtime,0,0);
while(1)
{
num = 0;
for(i=0;i<7;i++)
{
num = num*10+rand()%10;
}
mvwprintw(wnumb,1,2,"%07d",num);
refresh();
wrefresh(wnumb);
wrefresh(wtime);
usleep(500000);
}
endwin();
}
demo2:
使用两个进程实现信号的传递
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include <curses.h>
#include <math.h>
WINDOW *w;
int num = 0;
int isstop = 0;
void deal(int s)
{
isstop = (s==SIGUSR1) ? 1 : 0;
}
main()
{
int i = 0;
initscr();
curs_set(0);
noecho();
keypad(stdscr,TRUE);
keypad(w,TRUE);
w = derwin(stdscr,3,11,(LINES-3)/2,(COLS-11)/2);
box(w,0,0);
refresh();
wrefresh(w);
if(fork())
{
signal(SIGUSR1,deal);
while(1)
{
if(isstop == 1)
{
pause();
isstop = 0;
}
num = 0 ;
for(i=0;i<7;i++)
{
num = num*10 + rand()%10;
}
mvwprintw(w,1,2,"%07d",num);
refresh();
wrefresh(w);
usleep(100000);
}
}
else
{
while(1)
{
getch();
kill(getppid(),SIGUSR1);
}
}
endwin();
}
4.信号的可靠与不可靠以及信号的含义
信号有丢失(信号压缩)
由于历史的缘故:信号有压缩的需求
可靠信号与不可靠信号
早期信号1-31 31个信号,不可靠(与系统有关)
后期信号34-64 可靠信号(用户信号)
5.信号的操作
信号导致的问题
1.信号屏蔽
int sigprocmask(int how,//操作方式 SIG_BLOCK SIG_UNBLOCK SIG_SETMASK
const sigset_t*sigs,//操作的信号集合
sigset_t *oldsigs//返回原来操作的信号
);
1.1.声明一个信号集合
sigset_t sigs;
1.2.加入屏蔽信号
一组信号集合维护函数:
1.2.1.清空集合sigemptyset
1.2.2.添加信号到集合sigaddset
1.2.3.从集合删除信号sigdelset
1.2.4.添加所有信号到集合sigfillset
1.2.5.判定某个集合是否在其中sigismember
sigmask.c
#include <stdio.h>
#include <signal.h>
main()
{
int i = 0;
sigset_t sigs;
sigemptyset(&sigs);
sigaddset(&sigs,SIGINT);
sigprocmask(SIG_BLOCK,&sigs,0);
for(i=0;i<10;i++)
{
printf("%d\n",i);
sleep(1);
}
printf("i=%d\n",i);
sigprocmask(SIG_UNBLOCK,&sigs,0);
printf("over\n");
}
这个程序可以屏蔽ctrl+C
1.3.屏蔽信号
1.4.接触屏蔽
2.信号屏蔽的切换
int sigsuspend(sigset_t *sigs);
屏蔽新的信号,原来的信号失效
sigsuspend是阻塞函数,对参数信号屏蔽
对参数没有指定的信号不屏蔽,但当没有屏蔽的信号处理函数结束后返回
sigsuspend返回条件:
1、非屏蔽信号发生
2、该信号触发且有处理函数,且处理函数返回
作用:使原来屏蔽信号无效,开放原来的信号,使新的信号屏蔽,当某个信号处理函数处理完毕,sigsuspend恢复原来屏蔽信号,返回
3.查询被屏蔽的信号
sigpending(sigset_t *sig);
6.信号与进程间数据传递
sigqueue=kill
sigaction=signal
1.进程控制 sleep pause
2.理解信号的中断流程
3.发射信号(shell/code)kill,处理信号
4.alarm与setitmer
5.信号应用:实现多任务/进程之间通信
6.信号使用+sleep/pause控制进程
7.信号屏蔽
8.了解sigpending与sigsuspend使用