第一章 多进程与多线程
1 Linux 进程
1.1 进程基础
1.1.1 创建进程 fork()
- 返回值:
a) 成功:给父进程返回:子进程ID,给子进程返回:0
b) 失败:-1
//创建子进程
fork函数调用后发生的事情:
1) 分配子进程的虚拟空间
2) 将父进程的所有数据段中的内容拷贝到子进程对应的段中
3) 父子进程共享代码段
4) fork函数分别给父子进程返回一个值:给父进程返回:子进程ID,给子进程返回:0
5) fork返回后,父子进程同时从fork()调用的下一条语句开始执行
- 例如
int main(void)
{
pid_t pid;
pid = fork();
if (pid < 0) {
perror("fork");
exit(1);
}
else if (pid > 0) /* 父进程执行的代码 */
{
printf("我是爸爸:\n");
while (1)
{
printf("每天要赚钱\n");
sleep(1);
}
}
else /* 子进程执行的代码 */
{
printf("我是儿子:\n");
while (1)
{
printf("每天要花钱\n");
sleep(1);
}
}
return 0;
}
1.1.2 exec 函数族
//加载另一个程序到某个进程空间中执行
int execl(const char *path, const char *arg, ...);
int execlp(const char *file, const char *arg, ...);
int execle(const char *path, const char *arg, ..., char * const envp[]);
int execv(const char *path, char *const argv[]);
int execvp(const char *file, char *const argv[]);
int execvpe(const char *file, char *const argv[],char *const envp[]);
/* 注意:
1)通过程序名称寻找程序时,会去/bin 或 /usr/bin中找,如果程序在其他位置,则只能通过路径找
2)传递程序执行的格式时,最后一个参数必须是NULL,表示参数结束
3)当把一个程序加载到进程空间中执行时,进程中所有段中原来的数据和代码全部被该程序替换(覆盖)
*/
1.1.3 wait和waitpid
-
pid_t wait(int *status);
给任意一个子进程收尸,如果子进程没有结束,会使父进程阻塞,直到子进程结束为止。 参数 ------ 子进程结束状态 返回值 ------ 成功:被收尸的子进程的pid,失败:-1
-
id_t waitpid(pid_t pid, int *status, int options);
//给指定的子进程收尸 //参数1 ----- pid : pid>0: //给子进程ID号为pid的子进程收尸,如果指定的子进程没有结束,则一直阻塞。 pid=-1: //等待任何一个子进程退出,此时和wait作用一样。 pid=0: //等待其组ID等于调用进程的组ID的任一子进程。 pid<-1: //等待其组ID等于pid的绝对值的任一子进程 //参数2 ----子进程结束状态 //参数3 ---- options WNOHANG:若由pid指定的子进程并不立即可用,则waitpid不阻塞,此时返回值为0 WUNTRACED:若某实现支持作业控制,则由pid指定的任一子进程状态已暂停,且其状态自暂停以来还未报告过,则返回其状态。 0:同wait,阻塞父进程,等待子进程退出。
2 守护进程
2.1 创建步骤
-
1 创建子进程
pid = fork()
-
2 创建新会话
setsid()
-
3 忽略父进程结束产生的信号:SIGHUP影响
signal(SIGHUP,SIG_IGN);
-
4 创建子进程
pid = fork()
-
5 关闭所有文件描述符
int max_fd = sysconf(_SC_OPEN_MAX);
for(int i = 0; i < max_fd;i++)
close(i);
-
6 消除umask影响
umask(0);
-
7 修改守护进程的工作目录为系统根目录
chdir("/");
-
8 重定向标准输入,标准输出,标准错误输出
open("/dev/null",O_RDWR); dup(0); dup(0);
3 多线程
3.1 创建线程
#include <pthread.h>
int pthread_create(pthread_t *thread, const pthread_attr_t *attr,
void *(*start_routine) (void *), void *arg);
Compile and link with -pthread.
【注1】:参数3需要定义函数 void *my_fun(void * mydata), 传入my_fun
【注2】:编译时 + -lpthread
3.2 线程同步操作
- 初始化
#include <semaphore.h>
int sem_init(sem_t *sem, int pshared, unsigned int value);
-
等待/释放
#include <pthread.h> int sem_wait(sem_t *sem); int sem_post(sem_ *sem);
3.3 互斥访问
static pthread_mutex_t g_tMutex = PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_lock(&g_tMutex);
pthread_mutex_unlock(&g_tMutex);