《Linux C编程实战》笔记:创建线程

2024-01-07 20:03:27

上一章是进程,这一章是线程

有关线程进程的概念之类的请自行学操作系统吧,书里都是偏实战应用的

线程创建函数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)

等等,具体都在下面

文章来源:https://blog.csdn.net/ouliten/article/details/135384589
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。