ps aux 静态查询进程信息
ps ajx 查询进程之间关系
创建进程一般使用fork()函数,没有参数
返回值
On success, the PID of the child process is returned in the parent, and 0 is returned in the child. On failure, -1 is returned in the parent, no child process is created, and errno is set appropriately.
成功返回pid,pid为零代表子进程,小于零创建失败
#include
#include
#include
int main()
{
pid_t pid = fork();
return 0;
}
还有一种vfork()创建进程,需要配合execl来使用
getpid() 可以查询当前进程句柄,如果是大于零的值说明当前是父进程,如果等于零是子进程。
调用fork的进程为父进程,fork 创建的子进程把所有代码拷贝过去,从fork后面的部分开始执行
因为写的进程的代码段是相同的,可以通过pid的不同值来区分父进程还是子进程。
可以通过exec系列函数来把子进程进行替换
exec系列函数(execl、execlp、execle、execv、execvp)
头文件
extern char **environ;
原型:
int execl(const char *path, const char *arg, ...);
int execlp(const char *file, const char *arg, ...);
int execv(const char *path, char *const argv[]);
int execvp(const char *file, char *const argv[]);
int execle(const char *path, const char *arg, ..., char * const envp[]);
参数:
path参数表示你要启动程序的名称包括路径名
arg参数表示启动程序所带的参数,一般第一个参数为要执行命令名,不是带路径且arg必须以NULL结束
NULL为哨兵节点,exec初始化加载参数到NULL结束,必须写,否则exec报错。(NULL不可以用0代替)
返回值:成功返回0,失败返回-1
以上exec系列函数区别:
1,带l 的exec函数:execl,execlp,execle,表示后边的参数以可变参数的形式给出且都以一个空指针结束。
2,带 p 的exec函数:execlp,execvp,表示第一个参数path不用输入完整路径,只有给出命令名即可,它会在环境变量PATH当中查找命令
3,不带 l 的exec函数:execv,execvp表示命令所需的参数以char *arg[]形式给出且arg最后一个元素必须
是NULL
4,带 e 的exec函数:execle表示,将环境变量传递给需要替换的进程
代码
#include
int main()
{
printf("abc\n");
return 0;
}
//gcc print.c -o app
#include
#include
#include
int main()
{
pid_t pid =fork();//创建进程
if(pid == 0)//子进程
{
execl("./app","./app",NULL);//app是自己创建的程序
printf("child\n");
}
else if(pid > 0)//父进程
{
printf("parent\n");
}
return 0;
}
结果为parent 和abc 各打印一次,而child没有,所以如果需要子进程执行自定义代码或者任务,需要在fork后,exec之前完成。
创建进程后,子进程先于父进程死亡,父进程不知道,就会产生残留的pcb即僵尸进程,需要在父进程进行回收
wait(NULL) 是阻塞函数,回收僵尸进程
waitpid() 非阻塞回收
wait函数
调用一次wait只能回收一个进程
wait返回值:1.回收成功,wait返回值僵尸进程的pid 2.回收失败,wait 返回-1(什么时候失败? 在没有子进程的时候)
waitpid 回收函数 (比wait功能性更强,回收更为灵活)
waitpid(pid_t pid,int* status,int option);
1)pid:可以通过该参数指定waitpid回收
小于-1 跨组回收,指定组id,回收指定进程组种的(僵尸)子进 程,-5000(指定组id)
-1 回收任意子进程if
0 同组回收,父进程只能回收与自己同组的子进程
大于0 点名回收,指定子进程的pid,回收子进程3000 前面三个可以回收多个,>0回收一个 2)status 回收成功,传出子进程的退出信息,无论是wait还是waitpid,int* status 可以传NULL,不接收子进程退出信息
3)options: 可以通过选项参数,设计waitpid的工作状态以及回收方式
WNOHANG=可以通过该选项,将waitpid设置为非阻塞回收,没有子进程退出立即返回:
waitpid 返回值: 1)回收成功,子进程id
2)回收失败,wait返回-1 (没有子进程) 3)非阻塞回收,返回0,表示当前的子进程没有结束,无需回收
阻塞回收策略 和非阻塞回收策略
阻塞回收:阻塞工作需要挂起唤醒,如果挂起唤醒频繁,增大系统开销
非阻塞回收: 无挂起唤醒开销
阻塞回收:阻塞回收会对父进程造成一定影响,父进程自身的任务被搁置 无法进行推进
非阻塞回收:轮询回收,定时查看子进程是否需要回收,如果不需要返回执行自己的任务,如果需要则回收释放PCB残留
waitpid的使用代码
#include
#include
#include
#include
#include
int main()
{
int status;
pid_t pid = fork();//创建子进程
if(pid > 0)//大于零为父进程
{
printf("parent id : %d\n",getpid());
pid_t zid;
while((zid = waitpid(-1,0,WNOHANG)) != -1)//waitpid()函数的使用
{
if(zid > 0)
printf("child zid is %d\n",zid);
else if(zid == 0)
{
printf("continue\n");
}
sleep(1);
}
while(1) sleep(1);
}
else if(pid == 0)//子进程直接退出
{
printf("child id : %d\n",getpid());
sleep(5);
exit(0);//退出进程
//while(1) sleep(1);
}
return 0;
}
在后台默默运行,进行日志书写等任务
#include
#include
#include
#include
#include
#include
int main()
{
pid_t pid = fork();
// 1.创建子进程
if(pid > 0)
exit(0);
//2.创建新的会话
setsid();
//3.关闭输入输出
for(int i = 0;i < 3; i ++)
{
close(i);
}
//4.更改工作目录
chdir("/tmp");
//5.更改权限
umask(0);
6.创建文件
FILE* fd = fopen("mylog.txt","w+");
//7.定时更新
time_t t;
while(1)
{
t = time(NULL);
fprintf(fd,"%s",ctime(&t));
fflush(fd);
sleep(1);
}
//8.退出
//9.开机启动
return 0;
}
消息结构体
struct mass
{
int msgtype;
char text[1024];
}
随机生成key值
key_t keyid = ftok(“地址”,ID号(可任意));
创建消息队列,获得消息id
int massageid = msgget(刚才得到的keyid,权限(IPC_CREAT |0664));
发送消息
msgsnd(消息id,(void*)&消息结构体,消息结构体大小,权限(一般可填0));
接受消息
ssize_t ant = msgrcv(消息id,接收结构体地址,结果体大小,希望收到来自谁,权限)
ant为接收到的数量
msgctl(消息id,权限(IPC_RMID),0);
匿名管道是单向的,只能父子进程间使用
int pipefd[2];
pipe(pipefd) // 返回值为-1,则失败
pid_t pid = fork()
if(pid > 0)
{
close(pipefd[0]);
write(pipefd[1],szbuf,sizeof(szbuf));
close(pipefd[1]);
}
if(pid == 0)
{
char buf[1024];
close(pipefd[1]);
ssize_t ant = read(pipefd[0],buf,sizeof(buf));
if(ant >0)
{
printf("%s\n",buf);
}
close(pipefd[0];
}
更加方便,创建方式有两种
1:通过命令创建管道
int fd = open("mypipe",O_RDONLY);
char buf[1024];
ssize_t ant = read(fd,buf,sizeof(buf));
if(ant > 0)
printf("%s\n",buf);
close(fd);
创建管道
还需要在命令行输入 mkfifo mypipe//这是打开的管道的名字
#include
#include
#include
#include
#include
#include
#include
#include
int main()
{
int fd = open("filemap",O_CREAT|O_RDWR,0664);//打开一个文件,需要读写功能,没有则创建,
//给权限为0664
int filesize = ftruncate(fd,4096);//文件大小,不偏移文件大小为零
char *strbuf = (char*)mmap(0,4096,PROT_WRITE,MAP_SHARED,fd,0);//设置共享空间
strcpy(strbuf,"hello world");//写入数据
munmap(strbuf,4096);//回收
close(fd); //关闭文件句柄
return 0;
}
#include
#include
#include
#include
#include
#include
#include
#include
int main()
{
int fd = open("filemap",O_RDONLY);//打开文件,需要读的权限
int filesize = ftruncate(fd,4096);//文件大小为一页4096
char *szbuf = (char*)mmap(0,4096,PROT_READ,MAP_SHARED,fd,0);//读取共享空间内容
//strcpy(strbuf,"hello world");
printf("szbuf = %s\n",szbuf);//打印读取到的内容
munmap(szbuf,4096);//回收
close(fd); //关闭文件句柄
return 0;
}
命令行下输入:
mkfifo filemap;
#include
#include
#include
#include
#include
int main()
{
sigset_t newsig,oldsig;
sigemptyset(&newsig);
sigaddset(&newsig,2);
sigprocmask(SIG_SETMASK,&newsig,&oldsig);
while(1) sleep(1);
return 0;
}
#include
#include
#include
#include
#include
int main()
{
// sigset_t newsig,oldsig;
// sigemptyset(&newsig);
// sigaddset(&newsig,2);
// sigprocmask(SIG_SETMASK,&newsig,&oldsig);
struct sigaction newact,oldact;
newact.sa_handler = SIG_IGN;
newact.sa_flags = 0;
sigaction(2,&newact,&oldact);
while(1) sleep(1);
return 0;
}
#include
#include
#include
#include
#include
void myjob(int a)
{
printf("get c\n");
}
int main()
{
// sigset_t newsig,oldsig;
// sigemptyset(&newsig);
// sigaddset(&newsig,2);
// sigprocmask(SIG_SETMASK,&newsig,&oldsig);
struct sigaction newact,oldact;
newact.sa_handler = myjob;
newact.sa_flags = 0;
sigemptyset(&newact.sa_mask);
sigaction(2,&newact,&oldact);
while(1) sleep(1);
return 0;
}
时间竞争
alarm信号,定时发送信号
#include
#include
#include
#include
void myjob(int a)
{
}
void mysleep(int num)
{
struct sigaction newact,oldact;
newact.sa_handler = myjob;
newact.sa_flags = 0;
sigemptyset(&newact.sa_mask);
sigaction(14,&newact,&oldact);
alarm(num);
pause();
}
int main()
{
while(1)
{
mysleep(2);
printf("it has pasted two seconds\n");
}
return 0;
}
定时发信号的时候,多进程因为CPU时间资源的竞争,导致关键信号在被进程使用前提前处理,导致该进程依赖信号的功能产生异常
可以通过先屏蔽在解除屏蔽,来解决时序竞争问题
#include
#include
#include
#include
void myjob(int a)
{
}
void mysleep(int num)
{
//屏蔽信号
sigset_t newset,oldset;
sigemptyset(&newset);
sigaddset(&newset,14);
sigprocmask(SIG_SETMASK,&newset,&oldset);
//捕捉信号
struct sigaction newact,oldact;
newact.sa_handler = myjob;
newact.sa_flags = 0;
sigemptyset(&newact.sa_mask);
sigaction(14,&newact,&oldact);
alarm(num);
sleep(3);
//pause();
//挂起并解除屏蔽
sigsuspend(&oldact.sa_mask);
}
int main()
{
while(1)
{
mysleep(2);
printf("it has pasted two seconds\n");
}
return 0;
}
信号还可以携带信息
//发信息
#include
#include
#include
#include
int main(int agrc,char**agrv)
{
pid_t pid = atoi(agrv[1]);
int signum = atoi(agrv[2]);
union sigval sigvalue;
sigvalue.sival_int = 100;
sigqueue(pid,signum,sigvalue);
return 0;
}
//收信息
#include
#include
#include
#include
void myjok(int num, siginfo_t *info, void *constext)
{
printf("num is %d\ninfo is %d\n",num,info->si_int);
}
int main()
{
struct sigaction newact;
newact.sa_flags = SA_SIGINFO;
newact.sa_sigaction = myjok;
sigemptyset(&newact.sa_mask);
sigaction(SIGUSR1,&newact,NULL);
while(1);
return 0;
}
#include
#include
#include
#include
#include
void * threadproc (void *a)
{
while(1)
{
sleep(1);
printf("1\n");
}
}
int main()
{
pthread_t pid;
int err = pthread_create(&pid,NULL,&threadproc,NULL);
if(err)
{
printf("false is %s\n",strerror(err));
return 0;
}
while(1);
return 0;
}
pthread_self() 获取线程id
回收态: pthread_join(退出的线程id,退出码(返回的值)) 回收线程,阻塞
分离态: pthread_datach(线程id) 分离后会自动回收
处于回收态,不能进行分离
pthread_cancel(线程id); 发送推出码
pthread_testcancel() 空调用,可以执行一次系统调用
pthread_mutex_t mut; //定义锁
pthread_mutex_init(&mut,0); //初试化
pthread_mutex_destroy(&mut); // 清除
加锁
pthread_mutex_lock(&mut);//上锁
pthread_mutex_unlock(&mut);//开锁
安全灵活,效率不高
读的时候是共享的,写是互斥的
和互斥锁类似
#include
#include
#include
#include
pthread_rwlock_t mylock;
int ant = 0;
void *procthread1(void *a)
{
for(int i = 0; i< 1000;i ++)
{
usleep(1000);
pthread_rwlock_rdlock(&mylock);
//ant ++;
printf("thread id = [0x%x],read ant = %d\n",(unsigned int)pthread_self(),ant);
pthread_rwlock_unlock(&mylock);
}
}
void *procthread2(void *a)
{
for(int i = 0; i< 1000;i ++)
{
usleep(1000);
pthread_rwlock_wrlock(&mylock);
ant ++;
printf("thread id = [0x%x],write ant = %d\n",(unsigned int)pthread_self(),ant);
pthread_rwlock_unlock(&mylock);
}
}
int main()
{
pthread_rwlock_init(&mylock,0);
pthread_t pid[8];
for(int i = 0;i < 3; i ++)
{
pthread_create(&pid[i],NULL,&procthread1,0);
}
for(int i = 3; i < 8;i ++)
{
pthread_create(&pid[i],NULL,&procthread2,0);
}
for(int i = 0;i < 8;i ++)
{
pthread_join(pid[i],NULL);
}
pthread_rwlock_destroy(&mylock);
return 0;
}
可以通过设置互斥锁的属性,来把他变成进程间的共享锁
pthread_mutexattr_t
pthread_mutexattr_init();
pthread_mutexattr_getpshared(哪个,返回一个共享属性);
pthread_mutexattr_setpshared();//设置共享属性
进程共享锁
#include
#include
#include
#include
#include
#include
#include
#include
#include
typedef struct fdfd
{
pthread_mutex_t mlock;
int ncount;
}myshare;
int main()
{
int fd = open("myfi",O_RDWR|O_CREAT,0664);
ftruncate(fd,sizeof(myshare));
myshare *pshared = (myshare*)mmap(0,sizeof(myshare),PROT_WRITE, MAP_SHARED,fd,0);
pshared->ncount = 0;
pthread_mutexattr_t attr;
pthread_mutexattr_init(&attr);
pthread_mutexattr_setpshared(&attr,PTHREAD_PROCESS_SHARED);
pthread_mutex_init(&(pshared->mlock),&attr);
pid_t pid = fork();
if(pid > 0 )
{
for(int i = 0; i < 100; i++)
{
pthread_mutex_lock(&(pshared->mlock));
printf("parent id = %d ncount = %d \n",getpid(),++pshared->ncount);
pthread_mutex_unlock(&(pshared->mlock));
}
}
else if(pid == 0 )
{
for(int i = 0; i < 100; i++)
{
pthread_mutex_lock(&(pshared->mlock));
printf("child id = %d ncount = %d \n",getpid(),++pshared->ncount);
pthread_mutex_unlock(&(pshared->mlock));
}
}
printf("1\n");
pthread_mutex_destroy(&(pshared->mlock));
printf("2\n");
pthread_mutexattr_destroy(&attr);
printf("3\n");
munmap(pshared,sizeof(myshare));
printf("4\n");
return 0;
}