• 线程——进程与线程——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
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37

    例1:

    int main(void)
    {
    	printf("execl shang \n");
    	execl("./hello","./hello","hello","world",NULL);
    	printf("execl xia \n");
    
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    结果为:
    在这里插入图片描述
    可以看到,他并不执行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;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

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

    例三:

    #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;
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46

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

    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
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80

    例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;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41

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

    例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;
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25

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

    例三:创建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;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64

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

    以上就是今天的内容!

  • 相关阅读:
    振弦传感器和无线振弦采集仪在隧道安全监测的解决方案
    解密网络通信的关键技术(上):DNS、ARP、DHCP和NAT,你了解多少?
    hyoerf手记
    2022_NP_MIADPD
    Go 项目配置文件的定义和读取
    Java Socket实现简易多人聊天室传输聊天内容或文件
    【Python】PySpark 数据处理 ① ( PySpark 简介 | Apache Spark 简介 | Spark 的 Python 语言版本 PySpark | Python 语言场景 )
    ML 系统的日志记录
    量子计算在科技浪潮中的引领作用
    不可以涩涩!AI续写软件初体验;迁移学习路线图;谷歌新闻非官方搜索API;CS295『因果推理』2021课程资料;前沿论文 | ShowMeAI资讯日报
  • 原文地址:https://blog.csdn.net/m0_61988812/article/details/136308766