fork函数
fork()
是一个系统调用函数,用于在一个进程中创建一个新的进程,新进程与原进程具有相同的代码和数据空间,但拥有独立的内存空间、程序计数器(PC)和文件描述符等。在 Unix 和类 Unix 系统中,fork()
函数是创建新进程的基础。新进程被称为子进程,原进程被称为父进程。当
fork()
被调用时,操作系统会复制父进程的地址空间,包括所有的代码、数据和堆栈等。新进程和原进程将在fork()
调用处分别继续执行(并发执行)。区别在于fork函数在新进程将返回 0 值,而父进程将返回子进程的进程 ID。子进程会继承父进程打开的文件描述符,但是它们各自拥有独立的文件描述符表,因此对于一个文件的读写操作在两个进程中是相互独立的。如果出现错误,fork返回一个负值。
fork工作流程
/*
pid_t是数据类型,实际上是一个整型,通过typedef重新定义了一个名字,用于存储进程id.
getpid()函数返回当前进程的id号.
getppid()函数返回当前进程的父进程的id号.
*/
#include
#include
#include
int main(){
pid_t cid;
printf("Before fork Process id: %d\n",getpid());
cid = fork();
if(cid == 0){
//子进程执行的代码
printf("Children process id: %d, my parent process id:%d\n",getpid(),getppid());
for(int i = 0;i < 300;i++){
printf("hello\n");
}
}else{
//父进程执行的代码
printf("Parent process id: %d\n",getpid());
for(int i = 0;i < 300;i++){
printf("world\n");
}
}
return 0;
}
/*
验证性实验:
验证父子进程id号是否正确。
验证父子进程是否并发执行。可能结果不是,增大循环打印的次数试试。
*/
/*
wait函数会挂起调用它的进程,直到任意一个子进程结束(即子进程结束前父进程一直处于等待状态)。
sleep函数让调用进程睡眠指定时间(单位为second)。
这样组合可以让子进程执行完printf语句后睡眠3s之后父进程再执行printf语句。
*/
#include
#include
#include
#include
int main(){
pid_t cid;
int x = 100;
cid = fork();
if(cid == 0){
x++;
printf("In child x=%d\n",x);
sleep(3);
}else{
x++;
wait(NULL);
printf("In parent x=%d\n",x);
}
return 0;
}
/*
子进程和父进程输出的x的值是一样的。
因为子进程和父进程的内存空间是相互独立的。
*/
pthread_create函数
pthread_create()
是一个函数,用于创建一个新的线程。它是POSIX线程库(或者称为Pthreads库)提供的函数之一。
int pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine)(void *), void *arg);
thread
:一个指向pthread_t类型变量的指针,用于存储新创建的线程ID。attr
:一个指向pthread_attr_t类型变量的指针,用于指定新线程的属性。如果为NULL,则使用默认属性。start_routine
:一个指向函数的指针,新线程将从该函数开始执行。函数的参数是一个指向void类型的指针,返回值是一个指向void类型的指针。arg
:传递给start_routine
函数的参数。arg
是一个指向void类型的指针,用于传递给新线程的参数。具体来说,arg
指向的内存区域中存储了需要传递给新线程的数据或指针。 pthread_create()
函数的返回值是0,如果出现错误则返回一个非零的错误代码。
调用pthread_create()
函数后,系统会创建一个新线程,该线程会从指定的函数开始执行。新线程会与原来的线程并发运行,各自独立地执行自己的任务,但是它们共享相同的进程空间。新线程的执行状态和资源都是独立于原来的线程的,包括线程ID、线程栈、寄存器等。
pthread_join函数
pthread_join()
是一个 POSIX 线程库中的函数,它用于等待一个指定的线程结束。
int pthread_join(pthread_t thread, void **retval);
thread
参数是要等待的线程标识符
retval
参数是一个指向指针的指针,用于存储被等待线程的退出状态。
调用 pthread_join()
函数的线程会一直阻塞,直到指定的线程退出并且其资源被释放。如果线程已经退出,那么调用 pthread_join()
会立即返回。如果 retval
参数不是 NULL
,那么被等待线程的退出状态将被存储在 *retval
中。
pthread_join()
函数一般用于在多线程程序中同步各个线程的执行。通过等待其他线程的结束,主线程可以保证在这些线程完成它们的任务之前不会继续执行。
#include
#include
#include
#include
void* threadFunction(void* arg){
printf("In new thread\n");
}
int main(){
pthread_t tid; //这里的pthread_t与上文中pid_t相似
pthread_create(&tid,NULL,threadFunction,NULL);
pthread_join(tid,NULL);
printf("In main thread\n");
return 0;
}
/*
因为pthread的库不是linux系统的库,所以在进行编译的时候要加上 -lpthread
gcc -o threadDemo threadDemo.c -lpthread
*/
若将程序中的15行注释掉,则程序可能不会输出 “In new thread”。
原因:如果没有调用 pthread_join()
函数,那么主线程会继续向下执行,直到程序结束。此时,新线程还没有执行 printf 语句或者根本都没有开始执行,但是主线程已经退出了,因此新线程就会被强制终止。
是 C 和 C++ 语言中的头文件之一,用于多线程编程。在支持多线程的操作系统中,使用线程可以充分利用多核 CPU,提高程序的性能和响应速度。该头文件定义了一些重要的数据类型和函数,以实现线程的创建、管理、同步和通信。
pthread_t
数据类型用于标识一个线程,可以通过 pthread_create()
函数创建一个新线程,并返回该线程的 ID。pthread_t
类型的变量通常定义为全局变量,以便多个线程之间共享访问。
pthread_attr_t
数据类型用于设置新线程的属性,如线程的栈大小、调度策略等。可以使用 pthread_attr_init()
函数初始化一个线程属性对象,并通过 pthread_create()
函数将其传递给新线程。
pthread_mutex_t
数据类型用于实现互斥锁,以保护共享资源的访问。可以使用 pthread_mutex_init()
函数初始化一个互斥锁,并使用 pthread_mutex_lock()
和 pthread_mutex_unlock()
函数获取和释放锁。
pthread_cond_t
数据类型用于实现条件变量,以便线程之间进行同步和通信。可以使用 pthread_cond_init()
函数初始化一个条件变量,并使用 pthread_cond_wait()
、pthread_cond_signal()
和 pthread_cond_broadcast()
函数等待和唤醒条件变量。
pthread_key_t
数据类型用于创建线程特定数据的键,以便每个线程可以访问自己的私有数据。可以使用 pthread_key_create()
函数创建一个新的线程特定数据键,并使用 pthread_setspecific()
和 pthread_getspecific()
函数设置和获取线程特定数据。
是一个C语言标准库头文件,主要包含了一些对POSIX操作系统的标准函数和常量的声明。unistd
是UNIX Standard的缩写,因此该头文件通常被称为"UNIX Standard Header"。
该头文件包含了一些基本的系统调用和常量,如进程控制、文件操作、系统信息查询等,这些函数和常量可以用于跨平台的C程序开发。
该头文件中常用的函数和常量有:
getpid()
: 获取当前进程的ID。getppid()
: 获取当前进程的父进程ID。fork()
: 创建一个新进程。exec*()
: 替换当前进程的代码,用新的程序执行。pipe()
: 创建一个管道。chdir()
: 改变当前工作目录。getcwd()
: 获取当前工作目录。access()
: 检查文件是否存在及访问权限。close()
: 关闭文件描述符。read()
: 从文件描述符读取数据。write()
: 向文件描述符写入数据。sleep()
: 暂停当前进程一定时间。exit()
: 结束当前进程。STDIN_FILENO
, STDOUT_FILENO
, STDERR_FILENO
: 标准输入、标准输出和标准错误的文件描述符。需要注意的是,
头文件中的函数和常量是基于POSIX标准的,因此在跨平台开发时需要特别注意兼容性。
是一个C语言标准库头文件,用于定义一些系统数据类型和结构体,通常用于系统编程和底层操作。该头文件是Unix和类Unix操作系统中广泛使用的标准头文件之一。
该头文件定义了一些与系统数据类型和结构体相关的类型和常量,常用的有:
pid_t
: 进程ID类型uid_t
: 用户ID类型gid_t
: 组ID类型mode_t
: 文件权限类型off_t
: 文件偏移量类型size_t
: 无符号整数类型,通常用于表示内存块的大小等time_t
: 时间类型struct timeval
: 时间结构体struct timespec
: 时间结构体,用于支持纳秒级别的时间计算除此之外,该头文件还定义了一些常用的系统调用的函数原型,比如open()
、read()
、write()
等等。
需要注意的是,由于
是Unix和类Unix操作系统中广泛使用的标准头文件之一,因此在跨平台开发时需要特别注意兼容性。
是C和C++语言中的一个头文件,它包含了在系统级进程控制中使用的函数和宏。该头文件定义了一些用于等待进程状态改变的函数,如wait()
、waitpid()
等。在Unix和类Unix系统中,这些函数是非常有用的,可以用于父进程等待子进程结束,获取子进程的退出状态、资源使用情况等信息。
该头文件的主要内容如下: