线程——进程与线程——day10

今天主要内容是进程与线程中的线程以及一小部分遗留的进程的接口:exec函数族,接下来主要就是介绍exec函数族、线程的概念以及其函数接口

1.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:在系统指定目录下查找文件

    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:

int main(void)
{
	printf("execl shang \n");
	execl("./hello","./hello","hello","world",NULL);
	printf("execl xia \n");

	return 0;
}

结果为:
在这里插入图片描述
可以看到,他并不执行printf(“execl xia \n”);
在execl中,第一个参数是地址,第二个参数一般为文件名,如果不需要可以不写,但是最后一个参数必须是NULL。

例二:我们看一下execlp是怎么运行的

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

	printf("======================\n");
	printf("PATH:%s\n",getenv("PATH"));
	printf("======================\n");
	getcwd(tmpbuff,sizeof(tmpbuff));
	setenv("PATH",tmpbuff,1);
	printf("======================\n");
	printf("PATH:%s\n",getenv("PATH"));
	printf("======================\n");

	printf("shangmian\n");
	execlp("hello","hello","hoe","are","you",NULL);
	perror("fail to execlp");
	printf("xiamian\n");
	return 0;
}

结果:
在这里插入图片描述

例三:

#include"head.h"

int Mysystem(const char *pcommand)
{
	char tmpbuff[1024] = {0};
	char *parg[10] = {NULL};
	int cnt = 0;
	pid_t pid;

	strcpy(tmpbuff,pcommand);
	
	parg[cnt] = strtok(tmpbuff," ");
	cnt++;

	while(NULL != (parg[cnt] = strtok(NULL," ")))
	{
		cnt++;
	}

	pid = fork();

	if(-1 == pid)
	{
		perror("fail to fork");
		return -1;
	}

	if(0 == pid)
	{
		execvp(parg[0],parg);
	}

	wait(NULL);

	return 0;
}

int main(void)
{
	printf("shang\n");
	Mysystem("ls -l");
	printf("xia\n");

	return 0;
}

结果:
在这里插入图片描述

2.线程

1.基本概念:
    线程:线程是一个轻量级的进程,位于进程空间内部,一个进程中可以创建多个线程

2.线程创建:
    线程独占栈空间,文本段、数据段和堆区与进程共享

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

4.线程消亡:
    与进程消亡是一样的

5.进程和线程的区别:
    进程是操作系统资源分配的最小单元
    线程是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选项  

    2.pthread_self
      pthread_t pthread_self(void);
      功能:
        获得调用该函数线程的ID  

    练习:创建三个线程任务,线程打印 线程(TID:XXXX)开始执行

    3.pthread_exit 
      void pthread_exit(void *retval);
      功能:
        让调用该函数的线程任务结束
      参数:
        retval:线程结束的值
    
    4.pthread_join 
      int pthread_join(pthread_t thread, void **retval);
      功能:
        回收线程空间
      参数:
        thread:线程的ID号
        retval:存放线程结束状态空间的首地址
      返回值:
        成功返回0 
        失败返回错误码

例1:创建三个线程任务,线程打印 线程(TID:XXXX)开始执行

#include"head.h"

void *thread1(void *arg)
{
	printf("Thread1:%#x Starting!\n",(unsigned int)pthread_self());

	return NULL;
}

void *thread2(void *arg)
{
	printf("Thread2:%#x Starting!\n",(unsigned int)pthread_self());

	return NULL;
}

void *thread3(void *arg)
{
	printf("Thread3:%#x Starting!\n",(unsigned int)pthread_self());

	return NULL;
}

int main(void)
{
	pthread_t tid[3];
	void *(*p[3])(void *) = {thread1,thread2,thread3};
	int i = 0;

	for(i = 0;i < 3;++i)
	{
		pthread_create(&tid[i],NULL,p[i],NULL);
	}

	while(1)
	{

	}

	return 0;
}

结果:
在这里插入图片描述

例2

#include"head.h"

void *thread(void *arg)
{
	printf("Thread(TID):%#x Starting!\n",(unsigned int)pthread_self());	//获得调用该函数线程的ID  
	sleep(5);
	printf("Ending!\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);	//回收线程空间
	printf("%s\n",(char *)arg);	

	return 0;
}

结果:
在这里插入图片描述

例三:创建4个线程任务,任务一循环间隔1s打印"采集线程正在执行", 任务二循环间隔2s打印"存储线程正在执行",任务三循环间隔5s打印"告警线程正在执行",任务四循环间隔10s打印"日志线程正在执行"

#include"head.h"

void *thread1(void *arg)
{
	while(1)
	{
		printf("Pthread:%d 采集线程正在执行\n",(unsigned int)pthread_self());
		sleep(1);
	}
	return NULL;
}
void *thread2(void *arg)
{
	while(1)
	{
		printf("Pthread:%d 存储线程正在执行\n",(unsigned int)pthread_self());
		sleep(2);
	}
	return NULL;
}
void *thread3(void *arg)
{
	while(1)
	{
		printf("Pthread:%d 告警线程正在执行\n",(unsigned int)pthread_self());
		sleep(5);
	}
	return NULL;
}

void *thread4(void *arg)
{
	while(1)
	{
		printf("Pthread:%d 日志线程正在执行\n",(unsigned int)pthread_self());
		sleep(10);
	}
	return NULL;
}

int main(void)
{
	pthread_t tid[4];
	void *(*p[4])(void *) = {thread1,thread2,thread3,thread4};
	int i = 0;
	int ret = 0;

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

	while(1)
	{

	}

	return 0;
}

结果:
在这里插入图片描述

以上就是今天的内容!

  • 13
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值