C进程控制--上篇

基础

1.进程是一个动态的实体,是程序的一次执行过程。
2.进程是在内存中,程序是在硬盘中。
3.进程是操作系统资源分配的基本单位。
4.区别进程、线程、程序。
5.线程在进程内部,是比进程更小的能独立运行的基本单位。
6.线程不拥有系统资源,与其他线程共享进程的全部资源。
7.一个线程可撤销另一个线程,同一进程中多个线程并行执行。
8.进程树的顶端是一个控制进程,由一个名为init的程序执行,该进程是所有用户进程的祖先。系统启动时,操作系统创建一些进程他们管理和分配系统资源,这些进程是系统进程。

linux进程的结构

linux中进程分三部分:代码段+数据段+堆栈段
1.代码段:存放程序的可执行代码。
2.数据段:存放程序的全局变量、常量、静态变量。
3.堆栈段:堆用于存放动态分配的内存变量;栈用于函数调用,存放函数参数,函数内定义的局部变量。

linux进程状态

1.运行状态R(runnable):运行或者在运行队列等待。
2.可中断等待状态S(sleeping):等待某事件,但是可以被唤醒
3.不可中断等待状态D(uninterruptible sleep):等待某事件,不可唤醒,必须等到为止。
4.僵死状态Z(zombile):进程已终止,但进程描述符仍在,直到父进程调用wait()函数后释放
5.停止状态T(traced or stopped):进程因受到SIGSTOP、SIGSTP、SIGTIN、SIGTOU信号后停止运行或者该进程正在被跟踪。
注意:Linux下通过ps或pstree查看当前系统的进程树。
ps命令结果后缀
< 高优先级进程
N 低优先级进程
L 页不可换出内存
s 会话首进程
l 多线程进程
+ 进程位于前台进程组

进程的各种标识符

1.进程的唯一ID:一个非负数。
2.类型 pid_t
3.进程号是顺次向下使用;文件描述符是优先使用当前可用最小
4.学习ps命令

//进程其他标识信息;通过声明在头文件unistd.h中的函数获取
//其中typedef unsigned int pid_t;
#include <unistd.h>
pid_t getpid()  取当前进程ID    
pid_t getppid() 取进程父进程ID    
pid_t getuid()  取进程的实际用户ID,标识运行该进程的用户
pid_t geteuid() 取进程的有效用户ID,标识以什么用户身份来运行进程
pid_t getgid()  取进程的实际组ID,实际用户所属组的组ID
pid_t getegid() 获取进程的有效组ID,有效用户所属组的组ID

进程的内存映像

进程的内存映像:内核在内存中如何存放可执行程序文件。

//内存的低地址到高地址依次如下
1.代码段:只读,可被多进程共享,子进程共享父进程代码段,还复制父进程的数据段,,栈。
2.数据段:存储已被初始化变量包括全局变量和已被初始化的静态变量。
3.未被初始化数据段:存储未被初始化的静态变量(bss段)
4.:用于存放程序中动态分配的变量。
5.栈:用于函数调用,保存函数返回地址,函数的参数,函数内部定义的局部变量。
6.高地址还存了:命令行参数和环境变量			

创建进程

两种方式:
1.操作系统创建:进程间是平等的,一般不存在资源继承关系。
2.父进程创建:隶属关系,继承父进程的几乎所有资源。

注意1:系统进程:在OS启动时,OS会创建一些进程,它们承担管理和分配系统资源
注意2:系统调用fork()是创建新进程的唯一方法。
一般fork之后是父进程先运行还是子进程先运行是不确定的,取决于内核调渡算法。
注意3:操作系统一般让所有进程拥有同等的执行权。几个进程同时执行一个应用程序用处不多,一般是子进程通过exec函数执行其他程序。

#include<sys/types.h>
#include<unistd.h>
pid_t fork(void) 
/*成功调用当前进程后会在fork()处出分开
一个是父进程fork():父进程的返回值是刚创建子进程的ID;
一个是子进程fork():子进程返回值是0;
调用失败则不会分裂,函数返回-1

>>注意理解关键字duplicating 意味着拷贝,克隆,一模一样<<
*/

因此使用fork返回值来区分父子进程

#include<stdio.h>
#include<sys/types.h>
#include<unistd.h>
int main()
{
    pid_t pid;
    pid =fork();
    printf("------create process----");
    switch(pid)
   {
      case 0:
           printf("this is child process,child ID=%d,parent ID=%d\n",getpid(),getppid());
           break;
      case -1:
           printf("create process failed\n");
           break;
      default:
          printf("this is parent process,child ID=%d,parent ID=%d\n",pid,getpid());
           break;
    }
    exit(0);
}
/*
结果:
------create process----this is parent process,child ID=50201786,parent ID=45812546
------create process----this is child process,child ID=50201786,parent ID=45812546
*/
例子2#include<stdio.h>
#include<unistd.h>
#include<sys/types.h>
int main()
{
    pid_t pid;
    char * msg;
    int k;
    pid=fork();
    switch(pid)
    {
       case 0:
          msg="child process is running!";
          k=3;
          break;
       case -1:
          msg="creat process failed!\n";
          break;
       default:
          msg="parent process is running!";
          k=5;
          break;
    }
    while(k>0)
    {
       puts(msg);
       sleep(1);
       k--;
    }
    exit(0);
    return 0;
}
/*
结果:
child process is running!
parent process is running!
child process is running!
parent process is running!
child process is running!
parent process is running!
parent process is running!
parent process is running!
*/

注意1:fork进程失败,通常原因是父进程拥有子进程数超过规定。errno值为EAGAIN。如果是可供使用的内存不足,造成失败。errno值为ENOMEM。

注意理解fork()其关键字是duplicating 意味着拷贝,克隆,一模一样

子进程继承父进程的内容

0.子进程是对父进程的复制duplicating
1.用户ID、组ID、当前工作目录、根目录、打开的文件、创建文件时使用的屏蔽字
2.信号屏蔽字、上下文环境、共享的存储段、资源限制

子进程与父进程的区别

1.拥有不同的进程ID
2.fork返回值不同,父进程返回子进程ID,子进程返回0
3.不同父进程ID
4.子进程共享父进程打开的文件描述符,但父进程对文件描述符的改变不会影响子进程中的文件描述符
5.子进程不继承父进程设置的文件锁
6.子进程不继承父进程设置的未决信号
7.子进程的未决信号集被清空
8.子进程资源利用量清空

进程的消亡及释放资源

孤儿进程

孤儿进程:父进程先于子进程结束,子进程就变为孤儿进程,它由init收养

例子3#include<stdio.h>
#include<unistd.h>
#include<sys/types.h>
int main()
{
    pid_t pid;
    fflush(NULL);/*!!!刷新各种缓存流!!!*/
    pid=fork();
    int k=2;
    switch(pid)
    {
       case 0:
           while(k>0)
           {
              printf("A background process,PID=%d,Parent PID=%d\n",getpid(),getppid());
              k--;
              sleep(1);
           }
           break;
       case -1:
           printf("creat process failed");
           break;
       default:
           printf("I am parent process,my pid=%d\n",getpid());
           exit(0);
    }
    exit(0);
    return 0;
}
/*
结果:
I am parent process,my pid=5498
A background process,PID=5499,Parent PID=5498
A background process,PID=5499,Parent PID=1
*/

kill -9 pid 可以杀死进程

fork与vfork

相同点:
1.二者都是调用一次,返回两次

不同点:
第一点
1.fork创建进程:子进程完全复制父进程的资源,子进程独立于父进程,具有良好并发性
2.vfork创建进程:系统并不完成复制父进程资源,父子进程共享父进程的地址空间, 即子进程完全运行在父进程的地址空间上,子进程对地址空间的任何修改,父进程都是可见的。
第二点
1.fork 创建一个子进程,哪个进程先运行,取决于系统调度。
2.vfork 创建一个子进程,保证子进程先运行,当子进程调用exit()或者exec之后,父进程才被调度。如果调用exec和exit之前进程要依赖父进程的某个行为,会造成死锁。
第三点
fork比vfork需要更多的系统资源
注意
1.使用vfork时,最好不要允许子进程修改与父进程共享的全局变量和局部变量
2.vfork创建子进程后先保证子进程运行完,在子进程调用exit或exec之前父进程是阻塞状态S,子进程是不可中断D。

特别注意
现在fork增加了写实拷贝技术,即对于只读的数据父子进程是共享相同的物理内存,若是其中有一个进程进行修改则单独复制一份就行修改并不改原来那份。

#include<stdio.h>
#include<unistd.h>
#include<sys/types.h>
int globvar=5;
int main()
{
    pid_t pid;
    int var=3,i;
  pid=fork();
  /*pid=vfork();*/
    switch(pid)
    {
        case 0:
             i=1;
             while(i-->0)
             {
                 printf("子进程正在运行!\n");
                 globvar++;
                 var++;
                 printf("睡眠前子进程中globvar=%d,var=%d\n",globvar,var);
                 printf("子进程sleep\n");
                 sleep(1);
             }
             printf("睡眠后子进程中globvar=%d,var=%d\n",globvar,var);
             break;
        case -1:
             printf("创建进程失败!");
             break;
        default:
             i=2;
             while(i-->0)
             {
                 printf("父进程正在运行!\n");
                 globvar++;
                 var++;
                 printf("睡眠前父进程中globvar=%d,var=%d\n",globvar,var);
                 printf("父进程sleep\n");
                 sleep(1);
             }
             printf("睡眠后父进程中globvar=%d,var=%d\n",globvar,var);
        }
    exit(0);
    return 0;
}
/*
fork结果:
子进程正在运行!
睡眠前子进程中globvar=6,var=4
子进程sleep
父进程正在运行!
睡眠前父进程中globvar=6,var=4
父进程sleep
睡眠后子进程中globvar=6,var=4
父进程正在运行!
睡眠前父进程中globvar=7,var=5
父进程sleep
睡眠后父进程中globvar=7,var=5
vfork结果
子进程正在运行!
睡眠前子进程中globvar=6,var=4
子进程sleep
睡眠后子进程中globvar=6,var=4
父进程正在运行!
睡眠前父进程中globvar=7,var=5
父进程sleep
父进程正在运行!
睡眠前父进程中globvar=8,var=6
父进程sleep
睡眠后父进程中globvar=8,var=6
*/
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
#include<iostream> #include <iomanip> using namespace std; typedef struct page { int num; int bl_num; int i; struct page *next; }p_list,*p_ptr; typedef struct memory { int data; struct memory *next; }m_list,*m_ptr; int wst[8][8]; int v,z,qy_f=0,qy_l=0,yh; void change_add(int bl_num,int me_s,int lo_ad) { int b,c; yh=lo_ad/me_s; b=lo_ad%me_s; c=bl_num*me_s+b; cout<<"页号和偏移量:"<<yh<<"---"<<b<<endl; cout<<"物理地址为:"<<hex<<c<<endl; } void init_page(p_ptr &l,m_ptr &k) { int m; m_ptr s,q; p_ptr r,p; k=new m_list; k->next=NULL; s=k; l=new p_list; l->next=NULL; r=l; for(m=0;m<v;m++) { p=new p_list; p->num=m; p->bl_num=-1; p->i=0; r->next=p; r=p; } r->next=NULL; for(m=0;m<z;m++) { q=new m_list; q->data=-1; s->next=q; s=q; } s->next=NULL; } void show_page(p_ptr l) { p_ptr r; r=l->next; cout<<"页号"<<" "<<"块号"<<" "<<"状态位"<<endl; while(r!=NULL) { cout<<" "<<r->num<<" "<<setw(2)<<r->bl_num<<" "<<r->i<<endl; r=r->next; } } void show_memory(m_ptr k) { m_ptr s; s=k->next; cout<<"主存"<<endl; while(s!=NULL) { cout<<s->data<<endl; s=s->next; } } void init_wst() { for(int i=0;i<8;i++) { for(int j=0;j<8;j++) { wst[i][j]=rand()%2; } } } void print_wst() { for(int i=0;i<8;i++) { for(int j=0;j<8;j++) { cout<<wst[i][j]<<" "; } cout<<endl; } } int rand_bl() { int bl_nu; for(int i=0;i<8;i++) { for(int j=0;j<8;j++) { if(wst[i][j]==0) { wst[i][j]=1; bl_nu=8*i+j+1; return bl_nu; } } } return bl_nu; } int pdk(m_ptr k) { int i=0; m_ptr s; s=k->next; while(s!=NULL) { if(s->data==-1) { i++; s=s->next; } else { return i; } } return i; } int mzf(m_ptr k,int page_num) { int i=0; m_ptr s; s=k->next; while(s!=NULL) { if(s->data==page_num) { return 1; } else { s=s->next; } } return 0; } int FIFO(p_ptr &l,m_ptr &k,int page_num,int bl_nu) { int m; p_ptr r; m_ptr s,t,u; u=new m_list; s=k->next; r=l->next; while(r!=NULL) { if(r->num==page_num&&r->i!=0) { break; } if(r->num==page_num&&r->i==0) { r->i=1; r->bl_num=bl_nu; qy_f++; } r=r->next; } if(pdk(k)!=0&&pdk(k)==z) { while(s!=NULL) { if(s->data==page_num) { show_page(l); show_memory(k); return 0; } s=s->next; } s=k->next; for(m=0;m<z-1;m++) { s=s->next; } s->data=page_num; z--; show_page(l); show_memory(k); return 0; } if(pdk(k)==0) { if(mzf(k,page_num)==1) { show_page(l); show_memory(k); return 0; } if(mzf(k,page_num)==0) { while(s->next!=NULL) { t=s; s=s->next; } t->next=NULL; r=l->next; while(r!=NULL) { if(r->num==s->data) { r->bl_num=-1; r->i=0; } r=r->next; } delete s; u->data=page_num; u->next=k->next; k->next=u; show_page(l); show_memory(k); } } } /*int LRU(p_ptr &l,m_ptr &k,int page_num,int bl_nu) { int m; p_ptr r; m_ptr s,t,u; u=new m_list; s=k->next; r=l->next; while(r!=NULL) { if(r->num==page_num&&r->i!=0) { break; } if(r->num==page_num&&r->i==0) { r->i=1; r->bl_num=bl_nu; qy_l++; } r=r->next; } if(pdk(k)!=0&&pdk(k)==z) { while(s!=NULL) { if(s->data==page_num) { show_page(l); show_memory(k); return 0; } s=s->next; } s=k->next; for(m=0;m<z-1;m++) { s=s->next; } s->data=page_num; z--; show_page(l); show_memory(k); return 0; } if(pdk(k)==0) { if(mzf(k,page_num)==1) { while(s->next!=NULL) { t=s; if(s->data==page_num) { } } show_page(l); show_memory(k); return 0; } if(mzf(k,page_num)==0) { while(s->next!=NULL) { t=s; s=s->next; } t->next=NULL; r=l->next; while(r!=NULL) { if(r->num==s->data) { r->bl_num=-1; r->i=0; } r=r->next; } delete s; u->data=page_num; u->next=k->next; k->next=u; show_page(l); show_memory(k); } } }*/ void main() { int lo_ad,bl_nu,bl_sz,ra_bl; p_ptr page; m_ptr memory; cout<<"请输入页表长度:"<<endl; cin>>v; cout<<"请输入块数:"<<endl; cin>>z; cout<<"请输入块的长度(b):"<<endl; cin>>bl_sz; init_wst(); init_page(page,memory); show_page(page); show_memory(memory); while(lo_ad!=-1) { ra_bl=rand_bl(); cout<<"请输入逻辑地址:"<<endl; cin>>hex>>lo_ad; change_add(ra_bl,bl_sz,lo_ad); if(yh>v-1) { cout<<"error"<<endl; continue; } cout<<dec; cout<<"FIFO:"<<endl; FIFO(page,memory,yh,ra_bl); cout<<"缺页数:"<<qy_f<<endl; } }

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值