您的位置:首页 > 其它

进程线程基础

2017-04-26 22:38 302 查看
一、进程
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);
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  线程 进程 api