一.exec函数族
extern char **environ;
int execl(const char *path, const char *arg, ... (后面跟的参数)
/* (char *) NULL */);
eg:
int main(void) //execl用法
{
printf("======================");
execl("./hello","./hello","艳阳","高照",NULL); //后面跟的“传参”的参数,优先在当前目录来找
return 0;
}
int execlp(const char *file, const char *arg, ... (区别l在于在哪个目录下寻找需要执行的文件)
/* (char *) NULL */);
eg:
extern char **environ; //execlp的用法
int main(void)
{
int i = 0;
char tmpbuff[1024] = {0};
printf("===================/n");
for (i = 0; environ[i] != NULL; i++)
{
printf("environ[%d] = %s\n", i, environ[i]); //打印程序运行时的隐藏运行文件
}
printf("===================\n");
printf("PATH:%s\n",getenv("PATH")); //获取PATH中的路径,此时是未改变的路径,是优先在系统下寻找
printf("===================\n");
getcwd(tmpbuff,sizeof(tmpbuff)); //获取当前路径
setenv("PATH",tmpbuff,1); //将原本为改变的路径更改为获取的当前路径经,代表在当下路径寻找文件
printf("PATH:%s\n",getenv("PATH")); //验证更改后的路径
printf("===================\n");
execlp("hello","hello","艳阳","高照",NULL);
return 0;
}
int execle(const char *path, const char *arg, ...
/*, (char *) NULL, char * const envp[] */);
int execv(const char *path, char *const argv[]);
eg:
int main(void) //execv用法
{
char *ch[10] = {"./hello","艳阳","高照",NULL};
printf("======================");
execv("./hello",ch); //后面跟的指针数组首地址,优先在当前目录寻找
return 0;
}
int execvp(const char *file, char *const argv[]);
eg:
int MySystem(const char *pcommand) //函数,实现调用ls功能
{
char commandbuf[1024] = {0};
char *parg[10] = {NULL};
int cnt = 0;
pid_t pid;
strcpy(commandbuf,pcommand); //pcommand是一个常量,要变量才能使用strtok,所以将它放在数组中
parg[cnt] = strtok(commandbuf," "); //第一次分割字符串放在parg【0】中
cnt++;
while((parg[cnt] = strtok(NULL," "))!=NULL) //后续分割,当返回值为NULL代表识别不到,停止
{
cnt++;
}
pid = fork(); //建立子程序用来执行execvp,以防父程序用完execvp后程序结束,无法执行后面的
if(pid == -1)
{
perror("fail to fork");
return -1;
}
if(pid == 0)
{
execvp(parg[0],parg); //parg[0]是一个ls功能,在bin中储存,parg是一个指针数组,存放的指令
}
wait(NULL); //回收子进程空间
return 0;
}
int main(void)
{
printf("shang\n"); //测试主程序运行
MySystem("ls -l"); //调用函数
printf("xia\n"); //测试主程序运行
return 0;
}
int execvpe(const char *file, char *const argv[],
char *const envp[]);
功能:
利用进程空间执行另外一份代码
l:参数以列表形式传递
v:参数以指针数组形式传递
e:更新环境变量
p:在系统指定目录下查找文件
getenv
char *getenv(const char *name);
功能:
获得环境变量名对应的值
setenv
int setenv(const char *name, const char *value, int overwrite);
功能:
设置环境变量的值
参数:
name:环境变量名
value:环境变量的值
overwrite:非0 覆盖
0 不覆盖
返回值:
成功返回0
失败返回-1
二.线程
1.概念:
线程是一个轻量级的进程,位于一个进程空间的内部,一个进程可以创建多个线程
2.线程的创建:
线程独占 栈空间,文本段,数据段和堆区与进程程序
3.线程调度:
与进程调度是一样的,宏观并行,围观穿行
4.线程的消亡:
与进程消亡是一样的
5.进程和线程的区别:
进程是操作系统资源分配的最小单元
线程是CUP任务调度的最小单元
多个线程的任务调度的时候比进程更加节省资源空间
6.多进程多线程的优缺点:
从效率来说:多线程 > 多线程 --- 多线程只需要在同一进程空间切换,多进程需要在不同的空间切换
通信:多线程 > 多进程 --- 线程共享全局变量,可以通过全局变量实现数据通信 ;
进程空间是独立的,没有共享空间,通信实现比较复杂
通信实现:多进程 > 多线程 --- 线程共享空间操作时引发资源竞争 ; 进程没有共享空间,不存在资源竞争的问题
安全:多进程 > 多线程 --- 一个进程异常不会影响到其余空间 ; 一个线程异常结束会导致进程进程异常结束 , 进程异常结束 , 该进程内所有线程所有线程任务均无法向下执行。
7.线程相关的函数接口:
创建: pthread_create
退出: pthread_exit
回收: pthread_join
1.pthread_create
int pthread_create(pthread_t *thread, const pthread_attr_t *attr,
void *(*start_routine) (void *), void *arg);
功能:
在该进程中创建一个新的线程
参数:
thread:存放线程ID空间首地址
attr:线程属性空间首地址
start_routine:线程要执行的函数的入口
arg:给线程函数的参数
返回值:
成功返回0
失败返回错误码
编译时加 -lpthread选项
2.pthread_self
pthread_t pthread_self(void);
功能:
获得调用该函数线程的ID
练习:创建三个线程任务,线程打印 线程(TID:XXXX)开始执行------------------------------------------------
void *threadfun1(void *arg) //线程执行的函数入口1
{
printf("线程1(TID:%#x)开始运行!\n",(unsigned int)pthread_self());
return NULL;
}
void *threadfun2(void *arg) //线程执行的函数入口2
{
printf("线程2(TID:%#x)开始运行!\n",(unsigned int)pthread_self());
return NULL;
}
void *threadfun3(void *arg) //线程执行的函数入口3
{
printf("线程3(TID:%#X)开始运行!\n",(unsigned int)pthread_self());
return NULL;
}
int main(void)
{
int ret = 0;
int i = 0;
pthread_t tid[3];
void *(*th[10])(void *) = {threadfun1,threadfun2,threadfun3}; //函数指针数组
for(i=0;i<3;i++)
{
ret = pthread_create(&tid[i],NULL,th[i],NULL);
if(ret != 0)
{
perror("fail to pthread_create");
return -1;
}
}
while(1)
{
}
return 0;
}
3.pthread_exit
void pthread_exit(void *retval);
功能:
让调用该函数的线程任务结束
参数:
retval:线程结束的值
4.pthread_join
int pthread_join(pthread_t thread, void **retval);
功能:
回收线程空间
参数:
thread:线程的ID号
retval:存放线程结束状态空间的首地址
返回值:
成功返回0
失败返回错误码
eg:pthread_exit,pthread_join 用法示例
void *thread(void *arg)
{
printf("线程(TID: %#x)开始运行\n",(unsigned int)pthread_self());
sleep(3);
printf("线程即将结束\n");
pthread_exit("Game Over!"); //线程任务的结束
return NULL;
}
int main(void)
{
pthread_t tid;
void *arg = NULL;
pthread_create(&tid,NULL,thread,NULL); //线程任务的开始
pthread_join(tid,&arg); //1参数:线程的ID号,2参数:存放线程结束状态空间的首地址
printf("arg = %s\n",(char *)arg);
return 0;
}