Linux进程与线程之二
2015-10-10 10:55
399 查看
每日一结
一 字符串分割函数
char *strtok(char *str, const char *delim);
功能:根据分隔符号来分割字符串
参数:
@str 第一次:字符串首地址 后面传递:NULL [告诉strtok函数接着上一次后面操作]
@delim 分割字符串
返回值:
成功返回子串的首地址,结束返回NULL
(对于这个函数的具体用法,自己man page。在string.c中,还可以看strtok()函数的源代码,有空可以看看它的实现)
二 exec函数族
e:执行程序的时候,可以给程序传递环境变量
int execle(const char *path, const char *arg,..., char * const envp[]);
char *envp[] = {"PATH=/home/linux","TEST=HELLO WORD",NULL};
注:对于exec函数族,要学会使用其中的一种,并且明白v , p ,e各自都代表什么意思。并明白什么时候去使用exec函数族中的函数。
(待整理)
三 回收僵尸态子进程
僵尸态子进程产生的原因 :
一个进程在调用exit命令结束自己的生命的时候,其实它并没有真正的被销毁,而是留下一个称为僵尸进程(Zombie)的数据结构(系统调用exit,它的作用是使进程退出,但也仅仅限于将一个正常的进程变成一个僵尸进程,并不能将其完全销毁)。在Linux进程的状态中,僵尸进程是非常特殊的一种,它已经放弃了几乎所有内存空间,没有任何可执行代码,也不能被调度,仅仅在进程列表中保留一个位置,记载该进程的退出状态等信息供其他进程收集,除此之外,僵尸进程不再占有任何内存空间。它需要它的父进程来为它收尸,如果他的父进程没安装SIGCHLD信号处理函数调用wait或waitpid()等待子进程结束,又没有显是忽略该信号,那么它就一直保持僵尸状态,如果这时父进程结束了,那么init进程自动会接手这个子进程,为它收尸,它还是能被清除的。但是如果父进程是一个循环,不会结束,那么子进程就会一直保持僵尸状态,这就是为什么系统中有时会有很多的僵尸进程。
1.为什么要回收?
僵尸态子进程已经结束,它占用大部分资源已经释放,但是仍然保留PID资源。
如果僵尸态子进程过多,会导致PID资源耗尽,创建子进程失败。
注:cat /proc/sys/kernel/pid_max可以查看操作系统中pid的个数。
2.pid_t wait(int *status)
功能:回收僵尸态子进程
参数:
@status 获取进程结束状态
返回值:
成功返回僵尸态子进程的PID,失败返回-1(没有子进程)
-----------------------------------------------------
特点:
(1)任意子进程进入僵尸态都可以处理
(2)如果没有子进程进入僵尸态,阻塞调用者
-----------------------------------------------------
3.pid_t waitpid(pid_t pid, int *status, int options);
功能:等待一个特定PID的子进程状态发生改变[R->T ,T->R, R->Z]
参数:
pid 是一个指定子进程的PID
pid -1[任意一个子进程]
@status 获取子进程状态
@options 0:阻塞的方式调用 WNOHANG:非阻塞的方式调用
返回值:
(1)返回子进程的PID
(2)返回0 [采用非阻塞方式调用且没有子进程状态发生改变]
(3)-1 [没有它处理的子进程]
(明白wait()和waitpid()函数的区别,并且要知道什么时候去用wait()函数,什么时候去用waitpid()函数)
参考笔记
代码分析如下:
四 exit(),_exit(),return 之间的区别
return : C语言的关键字,用于一个函数的返回。在main函数中的时候,用于结束一个进程
exit() : 是一个系统调用函数,任何地方调用它,都会结束当前进程,并且将缓存的数据进行刷新
_exit() : 是一个系统调用函数,任何地方调用它,都会结束当前进程,并且不会将缓存的数据进行刷新
五 Linux 守护进程
(1)创建子进程,父进程退出
(2)在子进程中创建的新会话 [setsid() : 调用者不能是组长进程]
(3)改变进程的工作目录到"/"
(4)重设文件掩码 umask(0)
(5)关闭不需要的文件描述符号 [0,1,2]
注:创建完守护进程之后,一定要记得将其杀死,不然它会一直运行,那会占用你很大的磁盘空间。需要用信号将其杀死。
六 普通用户运行程序,创建的进程拥有超级用户权限
RUID:标识创建进程的用户
EUID:标识进程的访问权限
SUID:保存EUID
(注:课下自己查询一下RUID,EUID,SUID,可参考man page和鸟哥私房菜)
-----------------------------------------------------------
如果可执行文件set-id-bit 被设置,运行这个程序创建的进程,其EUID由文件所有者决定
注:自己去弄清楚为什么要设置这一步?
-----------------------------------------------------------
<1>改变文件的所有者为root
sudo chown root 可执行文件
<2>打开set-id-bit
sudo chmod u+s 可执行文件
注:组长不能创建新会话
练习:
写一个守护进程写时间日志 [每次将系统时间写入文件]
参考代码如下:
参照笔记写其代码分析:
七 多线程编程
线程特点:
(1)多个线程共享同一个进程的地址空间
(2)多个线程参与统一调度
线程私有资源:
(1)线程ID
(2)一组寄存器值
(3)私有栈资源
...
线程间共享的资源:
(1)整个进程的地址空间
(2)全局变量
...
1.创建线程
int pthread_create(pthread_t *thread, const pthread_attr_t *attr,
void *(*start_routine) (void *),
void *arg
);
功能:创建一个线程
参数:
@thread 获得线程ID
@attr NULL:默认的属性
@start_routine 线程执行的函数
@arg 传递给线程执行函数传递参数
返回值:
成功返回0,失败返回错误码
注:
I. 在创建线程的时候,老师解压了一个线程库,自己课后百度一下。还有就是这个线程函数:pthread_create()。再一个就是因为这个线程库是第三方库,所以需要在编译时加上 -l库名
II. 对于最后一个参数,对于其数据类型void,看是否可以传其他的数据类型的参数,自己课下去验证一下。(关键还是得弄明白void这个数据类型)
III.主线程和子线程共用哪些资源?以及线程与进程的区别?
练习:
1.创建一个线程,传递多个参数个线程函数
int int_data = 100;
short short_data = 200;
char char_data = 50;
在这个线程函数中输出这些参数的值
代码示例如下:
代码分析如下:
注:I.在线程中,自己查看man page可以知道,传递给函数中的参数只有一个,所以若想传递多个参数,可以打包成结构体,然后再依次访问。
II.熟悉线程的创建流程,自己课下可以man page一下
晚间任务:
int main()
{
1.用open函数读写方式打开一个文件,文件不存在则创建,文件存在则清空
2.创建一个子线程,给线程传递的参数是文件描述符号
子线程:从文件中读取数据,然后输出
主线程:读取用户输入的字符串,然后写入文件
注意 :如果用户输入的是"quit"字符串,则结束
(这个事情我们在进程中做过一次,回顾一下当时的思路)
return 0;
}
具体代码如下:
代码分析如下:
待思考的问题:
I.在switch,case语句中, break;语句不能让其退出,需要用goto语句,关于这一点,课下自己验证其正确性。
II.man一下getpid()函数,getppid()函数,atoi()函数和getenv()函数
III.对照一下自己写的代码和老师写的代码的出入之处并加以改进。
IV.对照着笔记去整理一下这篇文档
关注微信公众号获取更多资讯
一 字符串分割函数
char *strtok(char *str, const char *delim);
功能:根据分隔符号来分割字符串
参数:
@str 第一次:字符串首地址 后面传递:NULL [告诉strtok函数接着上一次后面操作]
@delim 分割字符串
返回值:
成功返回子串的首地址,结束返回NULL
(对于这个函数的具体用法,自己man page。在string.c中,还可以看strtok()函数的源代码,有空可以看看它的实现)
二 exec函数族
e:执行程序的时候,可以给程序传递环境变量
int execle(const char *path, const char *arg,..., char * const envp[]);
char *envp[] = {"PATH=/home/linux","TEST=HELLO WORD",NULL};
注:对于exec函数族,要学会使用其中的一种,并且明白v , p ,e各自都代表什么意思。并明白什么时候去使用exec函数族中的函数。
(待整理)
三 回收僵尸态子进程
僵尸态子进程产生的原因 :
一个进程在调用exit命令结束自己的生命的时候,其实它并没有真正的被销毁,而是留下一个称为僵尸进程(Zombie)的数据结构(系统调用exit,它的作用是使进程退出,但也仅仅限于将一个正常的进程变成一个僵尸进程,并不能将其完全销毁)。在Linux进程的状态中,僵尸进程是非常特殊的一种,它已经放弃了几乎所有内存空间,没有任何可执行代码,也不能被调度,仅仅在进程列表中保留一个位置,记载该进程的退出状态等信息供其他进程收集,除此之外,僵尸进程不再占有任何内存空间。它需要它的父进程来为它收尸,如果他的父进程没安装SIGCHLD信号处理函数调用wait或waitpid()等待子进程结束,又没有显是忽略该信号,那么它就一直保持僵尸状态,如果这时父进程结束了,那么init进程自动会接手这个子进程,为它收尸,它还是能被清除的。但是如果父进程是一个循环,不会结束,那么子进程就会一直保持僵尸状态,这就是为什么系统中有时会有很多的僵尸进程。
1.为什么要回收?
僵尸态子进程已经结束,它占用大部分资源已经释放,但是仍然保留PID资源。
如果僵尸态子进程过多,会导致PID资源耗尽,创建子进程失败。
注:cat /proc/sys/kernel/pid_max可以查看操作系统中pid的个数。
2.pid_t wait(int *status)
功能:回收僵尸态子进程
参数:
@status 获取进程结束状态
返回值:
成功返回僵尸态子进程的PID,失败返回-1(没有子进程)
-----------------------------------------------------
特点:
(1)任意子进程进入僵尸态都可以处理
(2)如果没有子进程进入僵尸态,阻塞调用者
-----------------------------------------------------
3.pid_t waitpid(pid_t pid, int *status, int options);
功能:等待一个特定PID的子进程状态发生改变[R->T ,T->R, R->Z]
参数:
pid 是一个指定子进程的PID
pid -1[任意一个子进程]
@status 获取子进程状态
@options 0:阻塞的方式调用 WNOHANG:非阻塞的方式调用
返回值:
(1)返回子进程的PID
(2)返回0 [采用非阻塞方式调用且没有子进程状态发生改变]
(3)-1 [没有它处理的子进程]
(明白wait()和waitpid()函数的区别,并且要知道什么时候去用wait()函数,什么时候去用waitpid()函数)
参考笔记
代码分析如下:
四 exit(),_exit(),return 之间的区别
return : C语言的关键字,用于一个函数的返回。在main函数中的时候,用于结束一个进程
exit() : 是一个系统调用函数,任何地方调用它,都会结束当前进程,并且将缓存的数据进行刷新
_exit() : 是一个系统调用函数,任何地方调用它,都会结束当前进程,并且不会将缓存的数据进行刷新
五 Linux 守护进程
(1)创建子进程,父进程退出
(2)在子进程中创建的新会话 [setsid() : 调用者不能是组长进程]
(3)改变进程的工作目录到"/"
(4)重设文件掩码 umask(0)
(5)关闭不需要的文件描述符号 [0,1,2]
注:创建完守护进程之后,一定要记得将其杀死,不然它会一直运行,那会占用你很大的磁盘空间。需要用信号将其杀死。
六 普通用户运行程序,创建的进程拥有超级用户权限
RUID:标识创建进程的用户
EUID:标识进程的访问权限
SUID:保存EUID
(注:课下自己查询一下RUID,EUID,SUID,可参考man page和鸟哥私房菜)
-----------------------------------------------------------
如果可执行文件set-id-bit 被设置,运行这个程序创建的进程,其EUID由文件所有者决定
注:自己去弄清楚为什么要设置这一步?
-----------------------------------------------------------
<1>改变文件的所有者为root
sudo chown root 可执行文件
<2>打开set-id-bit
sudo chmod u+s 可执行文件
注:组长不能创建新会话
练习:
写一个守护进程写时间日志 [每次将系统时间写入文件]
参考代码如下:
参照笔记写其代码分析:
七 多线程编程
线程特点:
(1)多个线程共享同一个进程的地址空间
(2)多个线程参与统一调度
线程私有资源:
(1)线程ID
(2)一组寄存器值
(3)私有栈资源
...
线程间共享的资源:
(1)整个进程的地址空间
(2)全局变量
...
1.创建线程
int pthread_create(pthread_t *thread, const pthread_attr_t *attr,
void *(*start_routine) (void *),
void *arg
);
功能:创建一个线程
参数:
@thread 获得线程ID
@attr NULL:默认的属性
@start_routine 线程执行的函数
@arg 传递给线程执行函数传递参数
返回值:
成功返回0,失败返回错误码
注:
I. 在创建线程的时候,老师解压了一个线程库,自己课后百度一下。还有就是这个线程函数:pthread_create()。再一个就是因为这个线程库是第三方库,所以需要在编译时加上 -l库名
II. 对于最后一个参数,对于其数据类型void,看是否可以传其他的数据类型的参数,自己课下去验证一下。(关键还是得弄明白void这个数据类型)
III.主线程和子线程共用哪些资源?以及线程与进程的区别?
练习:
1.创建一个线程,传递多个参数个线程函数
int int_data = 100;
short short_data = 200;
char char_data = 50;
在这个线程函数中输出这些参数的值
代码示例如下:
代码分析如下:
注:I.在线程中,自己查看man page可以知道,传递给函数中的参数只有一个,所以若想传递多个参数,可以打包成结构体,然后再依次访问。
II.熟悉线程的创建流程,自己课下可以man page一下
晚间任务:
int main()
{
1.用open函数读写方式打开一个文件,文件不存在则创建,文件存在则清空
2.创建一个子线程,给线程传递的参数是文件描述符号
子线程:从文件中读取数据,然后输出
主线程:读取用户输入的字符串,然后写入文件
注意 :如果用户输入的是"quit"字符串,则结束
(这个事情我们在进程中做过一次,回顾一下当时的思路)
return 0;
}
具体代码如下:
代码分析如下:
待思考的问题:
I.在switch,case语句中, break;语句不能让其退出,需要用goto语句,关于这一点,课下自己验证其正确性。
II.man一下getpid()函数,getppid()函数,atoi()函数和getenv()函数
III.对照一下自己写的代码和老师写的代码的出入之处并加以改进。
IV.对照着笔记去整理一下这篇文档
关注微信公众号获取更多资讯
相关文章推荐
- 作为一个新人,怎样学习嵌入式Linux -----韦东山老师
- linux命令:dmesg
- Linux设备驱动程序之三 ---- LED驱动程序的实现
- 关于linux mysql启动错误问题
- Linux设备驱动程序之二 ---- 完善上一节的驱动程序
- Linux设备驱动前的工作准备 ---- 内核的配置及Makefile编写
- Linux设备驱动之一 ---- 驱动的框架及其操作流程
- Linux下的V4L2的API编程总结
- linux查找文件命令总结
- linux内核MKDEV()宏
- Image , zImage 和 vmlinux的区别
- arm-linux-gcc的下载与安装
- Linux下C++的man安装及使用方法
- Linux串口编程详解
- Hadoop I 搭建Linux下Hadoop2.6.0伪分布式环境
- Linux启动过程详解
- Linux上的终端设备
- Alsa是Linux高级音频接口(百度文库无下载券抄来的)
- 史上最经典的Linux内核学习方法论
- Linux内核驱动fsync机制实现图解