一、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.线程退出
void pthread_exit(void *retval);
功能:退出一个线程任务
参数:
retval:向回收的线程传递的参数的地址(NULL表示不传递参数)
II.线程回收
int pthread_join(pthread t thread, void * *retval).
功能:回收线程资源空间
参数:
thread:要回收的线程ID
retvaf用来保存线程退出时传递的参数(NULL表示不传递参数)
返回值:
成功:0
失败-1
III:线程属性
1.分离属性:不需要被其他线程回收的线程称为分离属性得到线程,将来会被操作系统所回收
int pthread_detach(pthread_t thread);
功能:将线程设置为分离属性的线程
2.非分离属性:可以被其他线程回收或者结束的线程,称为非分离属性的线程(默认属性:非分离属性)
IV:线程回收策略:
1.分离属性的线程:不需要回收。(没有空闲的线程可以帮忙回收时)
2.非分离属性的线程:pthread_join()阻塞回收
7.线程间通信
全局变量通信
临界资源:多个线程可以同时访问的资源称为临界资源:比如,全局变量、共享内存区域等
如何解决资源竞争问题:
1)互斥机制:多个线程访问临界资源时,具有排他性访问的机制(一次只允许一个线程对该临界资源进行访问)
互斥锁->解决资源竞争问题。
步骤:
1.创建互斥锁:pthread_utex_t
2.初始化互斥锁:pthread_mutex_init
3.加锁:pthread_mutex_lock
4.解锁:pthread_mutex_unlock
5.销毁锁:pthread_mutex_destroy
int pthread mutex init(pthread mutex t *restrict mutex.const pthread mutexattr t*restrict attr)
功能:初始化互斥锁
参数:mutex:锁对象地址
attr:锁的属性(NULL:默认属性)
返回值:成功:0
失败:-1
int pthread_mutex_lock(pthread_mutex_t *mutex);
功能:加锁
int pthread_mutex_unlock(pthread_mutex_t *mutex);
功能:解锁
int pthread_mutex_destroy(pthread_mutex_t *mutex);
功能:销毁锁
四、线程相关代码
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;
}
2.让线程输出一个学生的信息
#include<stdio.h>
#include<pthread.h>
#include<unistd.h>struct stu
{int id;char name[20];
}Stu;void *task(void *arg)
{struct stu *student = (struct stu *)arg; printf("%d\n%s\n", student->id, student->name);return NULL;
}int main(int argc, char const *argv[])
{pthread_t tid;struct stu s = {1,"wang"};int ret = pthread_create(&tid, NULL, task, &s);if(ret != 0){printf("pthread_create error\n");return -1;}sleep(1);return 0;
}
3.线程模拟无人机工作
#include<stdio.h>
#include<pthread.h>
#include<unistd.h>void *task1(void *arg)
{ while(1){printf("主控模块正在运行\n");pthread_exit(NULL);}
}void *task2(void *arg)
{ while(1){printf("控制模块正在运行\n");pthread_exit(NULL);}
}void *task3(void *arg)
{ while(1){printf("图像采集模块正在运行\n");pthread_exit(NULL);}
}void *task4(void *arg)
{ while(1) {printf("图像发送模块正在运行\n");pthread_exit(NULL);}
}void *task5(void *arg)
{ while(1){printf("指令接收模块正在运行\n");pthread_exit(NULL);}
}int main(int argc, char const *argv[])
{pthread_t tid1;pthread_t tid2;pthread_t tid3;pthread_t tid4;pthread_t tid5;int ret1,ret2,ret3,ret4,ret5;ret1 = pthread_create(&tid1, NULL, task1, NULL);ret2 = pthread_create(&tid2, NULL, task2, NULL);ret3 = pthread_create(&tid3, NULL, task3, NULL);ret4 = pthread_create(&tid4, NULL, task4, NULL);ret5 = pthread_create(&tid5, NULL, task5, NULL);if(0 != ret1 && 0 != ret2 && 0 != ret3 && 0 != ret4 && 0 != ret5){printf("pthread_create error\n");return -1;}sleep(1);pthread_join(tid1, NULL);pthread_join(tid2, NULL);pthread_join(tid3, NULL);pthread_join(tid4, NULL);pthread_join(tid5, NULL);return 0;
}
4.加互斥锁解决资源竞争问题
#include <stdio.h>
#include <pthread.h>int num_g = 0;
pthread_mutex_t mutex;void *task1(void *arg)
{for (int i = 0; i < 100000; i++){pthread_mutex_lock(&mutex);num_g = num_g+1;printf("num_g = %d\n", num_g);pthread_mutex_unlock(&mutex);}
}void *task2(void *arg)
{for (int i = 0; i < 100000; i++){pthread_mutex_lock(&mutex);num_g = num_g+1;printf("num_g = %d\n", num_g);pthread_mutex_unlock(&mutex);}}int main(int argc, const char *argv[])
{pthread_t tid[2];pthread_mutex_init(&mutex, NULL);pthread_create(&tid[0], NULL, task1, NULL);pthread_create(&tid[1], NULL, task2, NULL);pthread_join(tid[0], NULL);pthread_join(tid[1], NULL);pthread_mutex_destroy(&mutex);return 0;
}