《嵌入式Linux应用编程(六):并发编程基础:多进程exec函数族及多线程基础》
一、exec函数族
在一个进程里面执行另一个文件
本质:将文本区的指令代码替换成exec要执行的指令
#include <unistd.h>
参数:path:要执行的可执行文件的路径和名称
arg:执行该可执行文件时需要传递的参数
NULL:参数传递结束标志
返回值:错误为1,正确不返回
int execlp(const char *file, const char *arg, .../* (char *) NULL */);
功能:从PATH指定的系统路径下寻找该可执行文件
参数:file:需要执行的可执行文件的名称(系统路径下已有的文件)
arg:执行该可执行文件时需要传递的参数
NULL:参数传递结束标志
int execle(const char *path, const char *arg, .../*, (char *) NULL, char * const envp[] */);
execle
函数允许自定义环境变量传递给新程序。参数 path
为可执行文件的完整路径,arg
为参数列表,envp
是一个字符串数组,表示新的环境变量(格式为 "KEY=value"
),以 NULL
结尾。
int execv(const char *path, char *const argv[]);
execv
与 execl
功能相同,但参数传递方式不同。execv
使用字符串数组 argv
传递参数(数组末尾需为 NULL
),适合动态生成参数的场景。
int execvp(const char *file, char *const argv[]);
execvp
结合了 execv
和 execlp
的特点:从系统路径查找可执行文件,并通过数组传递参数。参数 file
为文件名,argv
为参数数组(含命令自身)。
int execvpe(const char *file, char *const argv[],char *const envp[]);
execvpe
是 execvp
的扩展版本,支持自定义环境变量。参数 envp
为环境变量数组,格式与 execle
相同。非标准函数,需确保系统支持(如 GNU 扩展)。
代码
#include <stdio.h>int main(void)
{printf("Hello World!\n");return 0;
}
编译命令为gcc text.c -o hello
#include<stdio.h>
#include<unistd.h>int main(int argc, char const *argv[])
{//execl("./hello", "./hello", NULL);//execl("/bin/ls", "ls", "-l", NULL);//execlp("ls", "ls", "-l", NULL);//char *arg[] = {"ls", "-l", NULL};//execv("/bin/ls", arg);// char *arg[] = {"ls", "-l", NULL};// execvp("ls", arg);return 0;
}
l:list 列表
p:path 路径 : 系统路径
v:vector 容器
e:env 环境变量
二、system
system相当于调用了一次fork(),父进程等待子进程运行结束后,在进行运行
不调用system函数接口,实现system的功能
#include <stdio.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>int my_system(char *buff)
{char *arg[10] = {NULL};int i = 0;char cmd[512] = {0};strcpy(cmd, buff);arg[i] = strtok(cmd, " ");while (arg[i] != NULL){printf("arg[%d] = %s\n", i, arg[i]);i++;arg[i] = strtok(NULL, " ");}pid_t pid = fork();if (pid > 0){wait(NULL);}else if (0 == pid){execvp(arg[0], arg);}return 0;}int main(int argc, const char *argv[])
{printf("system : pid = %d\n", getpid());
// system("./hello");my_system("ls -l");printf("After system\n");return 0;
}
三、线程
1.什么是线程
轻量级的线程,可实现多任务的并发。
进程是操作系统资源分配的最小单位;
线程是操作系统任务调度的最小单位。
2.线程的创建
线程由某个进程创建。
进程创建线程时,会为其分配独立的8M的独立的栈区空间
线程所在的进程,以及进程中的其他线程,共用进程的堆区、数据区、文本区。
3.线程的调度
宏观并行,微观串行
4.线程的消亡
1)线程退出
2)回收线程资源空间
5.进程和线程的区别
1)进程
资源消耗:
进程是操作系统资源分配的最小单位;
资源开销大,每次创建都需要0-4G的虚拟空间
效率方面:
由操作系统创建,耗时比线程久;跨进程调度比跨线程慢
通信方面:
进程间不能之间通信,需要使用进程间通信机制(IPC)机制
安全性角度:
进程安全性比线程高,各进程空间独立
2)线程
资源消耗:
线程是操作系统任务调度的最小单位。
资源开销小,只需要所在进程为其开辟8M的栈区空间
效率方面:
由所在进程创建跨进程调度比跨线程调度慢:
通信方面:
通信简单,可以使用线程共享的区域进行通信(比如全局变量)
安全性角度:
线程没有进程安全,一个线程异常可能影响同一进程中所有线程
6.线程的相关编程
1)线程的创建
#include <pthread.h>int pthread_create(pthread_t *thread, const pthread_attr_t *attr,void *(*start_routine) (void *), void *arg);
功能:
创建一个新线程
参数:
thread:保存线程ID的变量地址
attr:线程属性的对象地址
NULL:按照默认属性创建
void *(*start_routine) (void *):函数指针,函数名start_routine,指向线程启动后要执行的任务(线程任务函数)
arg:为线程任务函数传递的参数
返回值:
成功:0
失败:非0
pthread—self():获取当前线程ID号
pthread_create是不是linux函数,编译和链接时要加-lpthread
进程创建线程后,进程不能先退出,加sleep()
2)线程调度;由操作系统调度
3)线程退出
I.线程退出
II.线程回收
四、线程相关代码
1.创建线程
#include<stdio.h>
#include<pthread.h>
#include<unistd.h>
void *task(void *arg)
{printf("I am thread : tid = %ld\n", pthread_self());
}int main(int argc, char const *argv[])
{pthread_t tid;int ret = pthread_create(&tid, NULL, task, NULL);if(ret != 0){printf("pthread_create error\n");return -1;}sleep(2);return 0;
}