上一章是进程,这一章是线程
有关线程进程的概念之类的请自行学操作系统吧,书里都是偏实战应用的
线程创建函数pthread_create
#include <pthread.h>
int pthread_create(pthread_t *thread, const pthread_attr_t *attr,
void *(*start_routine) (void *), void *arg);
pthread_t *thread
: 用于存储新线程的标识符的指针。const pthread_attr_t *attr
: 指向线程属性的指针,通常为 NULL,表示使用默认属性。void *(*start_routine) (void *)
: 指向新线程要执行的函数的指针,该函数应该接受一个void*
参数并返回一个void*
。void *arg
: 传递给start_routine
函数的参数。
注意:线程创建成功时,pthread_create函数返回0,若不为0则说明创建线程失败。常见的错误码为EAGAIN和EINVAL。前者表示系统限制创建新的线程,例如,线程数目过多;后者表示第2个参数代表的线程属性值非法。线程创建成功后,新创建的线程开始运行第3个参数所指向的函数,原来的线程继续运行.
主要是理解第三个参数,这个函数指针是什么意思呢?就是指定线程接下来要执行的程序。创建一个线程,总得要让他干活吧,这个参数就是传递一个函数指针指明线程要干的事。后面有例子可以参考。
那第四个参数就能理解了,函数指针指向的函数可能有参数,所以要在这里传递参数
pthread.h还有一些有用的函数调用
pthread_self
函数用于获取调用线程的线程 ID。
#include <pthread.h>
pthread_t pthread_self(void);
pthread_equal
函数用于比较两个线程的线程 ID 是否相等。
#include <pthread.h>
int pthread_equal(pthread_t thread1, pthread_t thread2);
pthread_t thread1
: 第一个线程 ID。pthread_t thread2
: 第二个线程 ID。函数返回值是一个整数,如果两个线程的 ID 相等,则返回非零值(真),否则返回零(假)。
pthread_once
函数用于确保一个特定的初始化函数(只执行一次)被多线程环境中的一个线程调用。该函数通常用于在多线程环境中执行某个初始化任务,确保初始化只会执行一次,即便有多个线程同时请求初始化。
以下是 pthread_once
函数的声明:
#include <pthread.h>
int pthread_once(pthread_once_t *once_control, void (*init_routine)(void));
pthread_once_t *once_control
: 一个指向pthread_once_t
类型的控制变量的指针,用于确保初始化函数只被执行一次。void (*init_routine)(void)
: 指向初始化函数的指针
示例程序1
这个示例演示线程创建
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<pthread.h>
void *thread(void *arg){
pthread_t newthid;
newthid=pthread_self();
printf("this is a new thread,thread ID= %u\n",newthid);
return nullptr;
}
int main(){
pthread_t thid;
printf("main thread,ID is %u\n",pthread_self());
if(pthread_create(&thid,nullptr,thread,nullptr)!=0){
printf("thread creation failed\n");
exit(1);
}
sleep(1);
exit(0);
}
值得说道的就是这个thread函数了,它的返回类型是void *,参数类型也是void *,这是pthread_create函数参数规定的,所以以后写线程执行函数只能这么声明,而且参数只能是一个void *。
在pthread_create函数里,最后一个参数是nullptr,因为我们这个例子的函数不需要使用arg,所以就传了一个空指针。
如果想传递很多值信息,可以用数组或者结构体的方式。
示例程序2
这个示例程序演示pthread_once的使用
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<pthread.h>
pthread_once_t once=PTHREAD_ONCE_INIT;
void run(void){
printf("fuction run is running in thread %u\n",pthread_self());
}
void *thread1(void *arg){
pthread_t newthid;
newthid=pthread_self();
printf("Current thread ID= %u\n",newthid);
pthread_once(&once,run);
printf("thread1 ends\n");
return nullptr;
}
void *thread2(void *arg){
pthread_t newthid;
newthid=pthread_self();
printf("Current thread ID= %u\n",newthid);
pthread_once(&once,run);
printf("thread2 ends\n");
return nullptr;
}
int main(){
pthread_t thid1,thid2;
pthread_create(&thid1,nullptr,thread1,nullptr);
pthread_create(&thid2,nullptr,thread2,nullptr);
sleep(1);
printf("main thread exit!\n");
exit(0);
}
可以看到run函数只在一个线程中运行了一次(这个线程可能是1也可能是2),另一个线程虽然调用了,但是未执行。
其中pthread_once的第二个参数只能是返回类型为void,参数为void的函数,毕竟函数声明就是这样写的。
PTHREAD_ONCE_INIT
是用于初始化pthread_once_t
变量的宏,它的定义为:
#define PTHREAD_ONCE_INIT 0
这个宏是一个常量,用于初始化
pthread_once_t
类型的变量,表示pthread_once_t
的初始状态。pthread_once
函数使用这个变量作为参数,确保其中的初始化函数只会被执行一次。
pthread_attr_t结构体
书上说的结构体定义如下
不过我在自己的Linux系统上看了我的pthread_attr_t结构体长这样
union pthread_attr_t
{
char __size[__SIZEOF_PTHREAD_ATTR_T];
long int __align;
};
#ifndef __have_pthread_attr_t
typedef union pthread_attr_t pthread_attr_t;
# define __have_pthread_attr_t 1
#endif
可能是Linux的不同?我用的是openeuler,内核好像是centos,这我暂时不是很懂。
不过长得不一样,用法很多还是一样的,这个结构体主要还是设置线程的属性的,一般的设置函数如下:
pthread_attr_init(&attr);//初始化
pthread_attr_setstacksize(&attr,1024);//设置栈大小
pthread_attr_setdetachstate(&attr,PTHREAD_CREATE_DETACHED);//是否脱离,这里设置的是脱离(detach)
等等,具体都在下面