进程线程基础

一、进程
1.进程属性
进程与程序
程序:磁盘文件,格式:elf readelf a.out
进程:elf文件执行过程,4G虚拟空间,代码+初始化数据段+未初始化数据段+堆+栈+env,命令行参数
进程状态
进程上下文:context(PC,reg,堆栈指针等)
进程模式
用户模式
空间地址0x0000 0000 -0xbfff ffff 3G空间,资源访问受限。
内核模式
空间地址0xC000 0000 -0xffff ffff 1G共享空间。
cpu 进程切换与模式切换
进程切换:进程交替执行,时间片结束或进程让出cpu(sleep_on()sleep_on_interruptible())-->进程进入睡眠态(Task_Un/interrupt)
模式切换:
cpu执行不同功能代码时,进行模式切换,表现为寄存器使用变化.
进程命令
nice+renice
priority PRI内核调整值。
nice 用户可调值
PRI(new) = PRI(old) + nice(-20~19)
nice设置一个将要运行的程序的优先级
nice -n 5 vim
ps -l
renice调整一个正在运行进程的优先级
renice 10 pid
2.进程api
创建
fork() :父进程返回子进程的id号,子进程返回0. 父子进程执行先后顺序不确定.子进程继承了父进程的属性(打开的文件,所在目录,所在的组,uid,关联终端);
vfork() :vfork() 完全不copy,共享父进程物理空间,不能同时操作变量.保证子进程先运行直到结束,然后再继续运行父进程。子进程结束要调用_exit()函数退出进程.否则数据出错
exec函数族: 函数执行成功不返回
execlp
execle
execv
execvp
execve
退出:exit()使用更多,清除缓冲区, _exit()
回收:wait(), waitpid();
system() ;系统调用成功后返回原函数继续执行。
相关宏:
EXIT_SUCCESS
EXIT_FAILURE
WIFEXITED(status); WEXITSTATUS(status);
WIFSIGNALED(status); WTERMSIG(status);
3.进程组:
Shell上的一条命令行形成一个进程组 
每个进程必定属于一个进程组,也只能属于一个进程组。
组中领头进程为进程组长,pgid==组长id
组长可退出
组一直存在到最后一个进程退出或加入了其他组。
getpgid() 获取组id
setpgid(0,0) 加入或创建组
会话:
一个会话又可以包含多个进程组.
一个会话对应一个控制终端.
登陆一次终端就会产生一个会话session
分为前台进程组(only one )和后台进程组
setsid();
可建立一个新的会话;如果调用该函数的进程不是进程组的领头进程, 该函数才能建立新的会话. 
调用setsid()之后, 调用进程将成为新会话的领头进程. 

3.守护进程
1、fork创建子进程,父进程退出
2、子进程创建新会话,setsid();
3、改变工作目录 chdir()/
4、设置权限掩码 umask(0);
5、关闭文件描述符 for (fd=0; fd<fdtablesize; fd++)
close(fd);
二、线程
1.线程
传统os调度单位:进程(资源私有,虚拟地址,文件描述符,信号处理)
缺点:上下文切换开销大
多任务协作涉及通信,提出线程。
2.线程基础
lwp
继承了进程taskstruct
没有专门的线程id,复用pid
没有设计单独的调度算法,使用原task_struct算法。
printf("t1=%lu\n", (long int)pthread_self() ); //获取当前线程的id,相当于进程中的getpid();
printf("pid=%d\n", getpid()); //子线程的
printf("pid=%d\n", gettid()); //man 爷爷说glibc可能不支持,获取tid不成功
printf("tid=%ld\n", syscall(SYS_gettid)); //获取子线程tid
3.线程api
pthread_create(&t1, NULL, fun, NULL);
pthread_join(t1, &buf);//void *buf;
pthread_exit();
pthread_cancel();
4.互斥
4.1 mutex互斥锁
第一步:
定义全局变量锁 pthread_mutex_t glock;
第二步:
初始化锁,为锁设置属性 pthread_mutex_init(&glock, NULL);
第三部:
线程1:
申请加锁 pthread_mutex_lock(&glock);
临界资源(代码)
解锁 pthread_mutex_unlock(&glock);
线程2:
申请加锁
临界资源(代码)
解锁
4.2 semaphore信号量(值为1)
第一步:
定义全局变量信号量 sem_t apple;
第二步:
初始化信号量,为信号量设置属性 sem_init(&apple, 0, 1);
第三部:
线程1:
P操作 sem_wait(&apple);
临界资源(代码)
解锁 sem_post(&apple);
线程2:
申请加锁
临界资源(代码)
解锁
5.同步
5.1定义两把锁
lock1, lock2 pthread_mutex_t lock1,lock2;
Step1:锁住lock2,释放lock1 pthread_mutex_lock(&lock2)
step2:执行lock1,完成后释放lock2 pthread_mutex_lock(&lock1)
pthread_mutex_unlock(&lock2)
step3:执行lock2,完成后释放lock1 pthread_mutex_lock(&lock2)
pthread_mutex_unlock(&lock1)
5.2信号量:
step1:
定义全局
sem_t apple, pencil;
step2:
初始化apple,pencil; 先执行的线程初始化为1
sem_init(&apple, 0, 1);
sem_init(&pencil, 0, 0);
step3:
线程1:
P操作apple sem_wait(&apple);
代码;
V操作pencil sem_post(&pencil);
线程2:
P操作pencil sem_wait(&pencil);
代码;
V操作apple sem_post(&apple);
6.线程API:
openlog("守护进程名",LOG_PID, LOG_DAEMON);
syslog(LOG_ERR, %s, "出错信息");
closelog();
syslog(SYS_gettid); 获取线程tid
三、ipc机制
IPC对象: IPC对象是 活动在内核级别的一种进程间通信的工具
1.共享内存
关键字
key = ftok();
获取ipc的id
shmid = shmget(key, 1024*N, 0666|..);
对空间进行映射
p=(..)shmat(shmid, NULL, 0);
读取数据
memcpy();
取消映射
shmdt(p)
读端删除ipc
shmctl(shm_id, IPC_RMID, NULL)
2.消息队列
先进先出,
存在内核中
按照消息一个一个读取,可以指定读取某个消息
创建或打开
msgget(key, 0666|IPC_CREAT)
添加消息
msgsnd(msg_qid, &msg, strlen(msg.msg_text)+1, 0);
读取消息
msgrcv(msg_qid, &msg, BUFSIZE, 0, 0);
msgrcv(msg_qid, &msg, BUFSIZE,N, 0);
删除消息队列
msgctl(msg_qid, IPC_RMID, NULL)
3.信号量
内核图
semget()
semop()
semctl();
初始化semctl(sid, 0, SETVAL, sun);
P操作
struct sembuf buf;
buf.sem_num = 0;
buf.sem_op = -1;
buf.sem_flg = SEM_UNDO;
semop(sdi, &buf, 1);
V操作
buf.sem_num = 0;
buf.sem_op = 1;
buf.sem_flg = SEM_UNDO;
semop(sid, &buf, 1);
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值