Day 2.exec函数族和线程的基本概念、相关函数接口

exec函数族

extern char **environ;

       int execl(const char *path, const char *arg, ...
                       /* (char  *) NULL */);
       int execlp(const char *file, const char *arg, ...
                       /* (char  *) NULL */);
       int execle(const char *path, const char *arg, ...
                       /*, (char *) NULL, 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[]);

功能:利用进程空间去执行另外一份代码

l:参数以列表形式传递

v:参数以指针数组形式传递

e:更新环境变量

p:在系统指定目录下查找文件

1)自定义一个程序(文件名为apple)

#include "head.h"

int main(int argc,const char *argv[])
{
	int i = 0;
	printf("=============================\n");

	printf("how are you!\n");
	for (i = 0; i < argc; ++i)
	{
		printf("argv[%d] = %s\n",i,argv[i]);
	}
	return 0;
}

2)int execl/int execv引用运行

#include "head.h"

int main(void)
{
//	char *argv[5] = {"./hello","apple","bullll",NULL};

	printf("1111111\n");
	execl("./apple","./hello","apple","bullll",NULL);    //以参数形式传递   第一个时要运行的文件路径 后面是传递的参数
//	execv("./apple",argv);	      //以指针数组形式传递  定义指针数组如上
	printf("222222222222222\n");

	return 0;
}

getenv

char *getenv(const char *name);

功能:获得环境变量名对应的值

setenv

int setenv(const char *name, const char *value, int overwrite);

功能:设置环境变量的值

参数:

name:环境变量名

value:环境变量的值

overwrite:非0   覆盖

                    0     不覆盖

返回值:成功返回0;失败返回-1

#include "head.h"

int main(void)
{
	char tmpbuff[1024] = {0};

	printf("================================\n");
	printf("PATH:%s\n",getenv("PATH"));                      //获得PATH的系统路径
	printf("================================\n");
	getcwd(tmpbuff,sizeof(tmpbuff));                        //得到将当前路径 并将其放到数组中
	setenv("PATH",tmpbuff,1);           //将PATH的路径替换为数组中的内容
	printf("=================================\n");
	printf("PATH:%s\n",getenv("PATH"));                       //打印替换后的路径
	printf("=================================\n");

	execlp("apple","./hell","apple","bullll",NULL);     //参数以列表形式 在系统路径下查找文件 并执行 注:第一个参数是要执行的文件名
	
	return 0;

}

system

int system(const char *command);

功能:执行shell命令

特点:传递一个命令参数,执行成功后,会回到原来程序运行的位置继续向下执行,而exec函数是执行失败后回到原来的位置继续向下执行;者两点注意区分。

#include "head.h"

int Msystem(const char *p)
{
	char tmpbuff[1024] = {0};
	char *parg[10] = {0};
	int cout = 0;

	strcpy(tmpbuff,p);                       //将传过来的字符串常量以字符串的形式给到数组中
	parg[cout] = strtok(tmpbuff," ");                //在第一个空格的地方分解字符串
	cout++;

	while ((parg[cout] = strtok(NULL," ")) != NULL)  //将剩余的字符串继续以空格分割 放到指针数组中
	{
		cout++;
	}

	pid_t pid;          
	pid = fork();   //创建一个子进程用来单独执行命令
	if (pid == -1)
	{
		perror("fail to fork");
		return -1;
	}

	if (pid == 0)                   
	{
		execvp(parg[0],parg);       //调用execvp函数 参数以指针数组的形式 在系统目录下找到该命令并执行
	}

	wait(NULL);     //当子进程结束 回收子进程

	return 0;
}



int main(void)
{
	printf("system上面!\n");
	Msystem("ls -l");                 //封装一个system函数
	printf("system下面!\n");

	return 0;
}

线程

1.基本概念

线程:是一个轻量级的进程,位于进程空间内部,一个进程可以创建多个线程

2.线程的创建

线程独占栈空间,文本段,数据段,和堆区与进程共享

3.线程的调度

与进程调度一样的:宏观并行,微观串行

4.线程的消亡

僵尸态:线程代码结束,空间没有被回收,称为僵尸线程

5.进程和线程的区别

1)进程是操作系统资源分配的最小的单元;

2)线程是CPU任务调度的最小单元(多线程的系统和调度比进程更节省CPU资源空间)

6.多线程和多进程的优缺点

效率:多线程 > 多进程

  多线程只需要在同一进程空间切换;

  多进程需要在不同空间中切换

通信:多线程 > 多进程

  线程共享全局变量,可以通过全局变量实现数据通信

  进程空间独立,没有共享空间,通信实现比较复杂

通信的实现:多进程 > 多线程

  线程共享空间是会引发资源竞争

  进程没有共享空间,不存在资源竞争的问题

安全:多进程 > 多线程

  一个进程异常不会影响其余进程空间

  一个线程异常结束会导致进程异常结束,进程异常结束,该进程内所有线程任务均无法向下执行

7.线程相关的函数接口

创建:fork       pthread_create

退出:exit       pthread_exit

回收:wait      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选项  

练习:

创建三个线程,并执行

/***************************************
 *一次创建多个不同的线程
 *每个线程执行不同的任务
 *可以定义一个函数指针数组进行遍历
 * ************************************/
#include "head.h"

void *threadfun1(void *argc)
{
	printf("线程1(%#x)开始!\n",(unsigned int)pthread_self());
	return 0;
}

void *threadfun2(void *argc)
{
	printf("线程2(%#x)开始!\n",(unsigned int)pthread_self());
	return 0;
}

void *threadfun3(void *argc)
{
	printf("线程3(%#X)开始!\n",(unsigned int)pthread_self());
	return 0;
}

int main(void)
{
	int ret = 0;
	int i = 0;
	pthread_t tid[3];
	void* (*tip[3])(void*) = {threadfun1,threadfun2,threadfun3};    //有一个void*返回值并有一个void*参数的函数指针数组

	for (i = 0; i < 3; ++i)
	{
		ret = pthread_create(&tid[i],NULL,tip[i],NULL);
		if (ret != 0)
		{
			perror("fail to pthread");
			return -1;
		}
	}

	while(1)
	{

	}

	return 0;
}

2. pthread_self

pthread_t pthread_self(void);

功能:

获得调用该函数线程的ID  

3.pthread_exit 

void pthread_exit(void *retval);

功能:

让调用该函数的线程任务结束

参数:

retval:线程结束的值

4.pthread_join 

int pthread_join(pthread_t thread, void **retval);

功能:

回收线程空间

参数:

thread:线程的ID号

retval:存放线程结束状态空间的首地址

返回值:

成功返回0 

失败返回错误码

示例:
#include "head.h"

void *thread(void* argc)
{
	printf("进程开始!(PID:%#x)\n",(unsigned int)pthread_self());

	printf("进程即将结束!\n");
	sleep(5);
	printf("结束!\n");
	pthread_exit("over!");

	return NULL;
}


int main(void)
{
	int ret = 0;
	pthread_t tid;
	void *gid = NULL;

	ret = pthread_create(&tid,NULL,thread,NULL);

	if (ret != 0)
	{
		perror("fail to pthread");
		return -1;
	}

	pthread_join(tid,&gid);
	printf("gid=%s\n",(char *)gid);


	return 0;
}

  • 28
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

我爱敲代码yx

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值