LinuxC线程

简介: LinuxC线程

1. 线程ID

1. 1 pthread_self()

获得当前线程的线程ID

#include <pthread.h>
pthread_t pthread_self(void);

1.2 pthread_equal()

比较两个线程ID是否相等

#include <pthread.h>
int pthread_equal(pthread_t t1, pthread_t t2);

2. 创建线程

2.1 pthread_create()

#include <pthread.h> 
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 类型的缓冲区,pthread_attr_t 数据类型定义了线程的各种属性(线程栈地址,栈大小等等),如果传递NULL表示使用默认属性创建线程

start_routine: 线程函数

arg: 线程函数的参数,是一个指针

返回值: 成功返回0;失败会返回错误码。

  • 编译时需要加上: -lpthread

3. 终止线程

线程的终止方式有三种:

  • return
  • 线程调用pthread_exit
  • 其他线程调用pthread_cancel

3.1pthread_exit()

调用 pthread_exit()相当于在线程的 start 函数中执行 return 语句,不同之处在于,可在线程 start 函数所调用的任意函数中调用 pthread_exit()来终止线程。

#include <pthread.h>
void pthread_exit(void *retval);

4. 回收线程

pthread_join()函数将会以阻塞的形式等待指定的线程终止,如果该线程已经终止,则 pthread_join()立刻返回。

pthread_join类似于进程的waitpid,但也有不同:

  • 线程之间的关系是对等的,进程中的任意线程均可调用 pthread_join()函数来等待另一个线程的终止
  • 不能以非阻塞的方式调用pthread_join
#include <pthread.h>
int pthread_join(pthread_t thread, void **retval);

5. 取消线程

5.1 pthread_cancel()

通过调用 pthread_cancel()库函数向一个指定的线程发送取消请求.

发出取消请求之后,函数 pthread_cancel()立即返回,不会等待目标线程的退出

#include <pthread.h>
int pthread_cancel(pthread_t thread);

5.2 pthread_setcancelstate()

设置本线程是否响应其他线程发来的取消线程请求

#include <pthread.h>
int pthread_setcancelstate(int state, int *oldstate);

state:

  • PTHREAD_CANCEL_ENABLE:线程可以取消,这是新创建的线程取消性状态的默认值,所以新建线程以及主线程默认都是可以取消的。
  • PTHREAD_CANCEL_DISABLE:线程不可被取消,如果此类线程接收到取消请求,则会将请求挂起,直至线程的取消性状态变为 PTHREAD_CANCEL_ENABLE。

5.3 pthread_setcanceltype()

如果线程的取消性状态为 PTHREAD_CANCEL_ENABLE,那么对取消请求的处理则取决于线程的取消性类型,该类型可以通过调用 pthread_setcanceltype()函数来设置,它的参数 type 指定了需要设置的类型,而线程之前的取消性类型则会保存在参数 oldtype 所指向的缓冲区中,如果对之前的类型不敢兴趣,Linux下允许将参数 oldtype 设置为 NULL.

#include <pthread.h>
int pthread_setcanceltype(int type, int *oldstate);
  • PTHREAD_CANCEL_DEFERRED:取消请求到来时,线程还是继续运行,取消请求被挂起,直到线程到达某个取消点为止,这是所有新建线程包括主线程默认的取消性类型。
  • PTHREAD_CANCEL_ASYNCHRONOUS:可能会在任何时间点(也许是立即取消,但不一定)取消线程,这种取消性类型应用场景很少,不再介绍!

5.4 取消点

取消点其实就是一些函数(通过man 7 pthreads查看有哪些,搜索Cancellation关键字),因为线程的某些操作可能是不能退出的,一旦退出会造成程序的运行发送一些不可预料的事情,故出现了取消点这个概念。在线程接收到取消请求时(并且设置了可接受取消请求),没运行到取消点之前是不会退出的。

如果线程没有上述的这些取消点,但我们又想要他取消,就可以使用该函数,目的就是产生一个取消点

#include <pthread.h>
void pthread_testcancel(void);

6. 分离线程

线程分离后能够自动回收线程资源,不需要我们写代码调用pthread_join去回收。该过程是不可逆的

一个线程即可将另一个线程分离,同时也可以将自己分离出去。

#include <pthread.h>
int pthread_detach(pthread_t thread);

7. 注册线程清理处理函数

与进程终止处理函数类似,线程在退出时也可去执行处理函数。

一个线程可以注册多个清理函数,这些清理函数记录在栈中,每个线程都可以拥有一个清理函数栈,栈是一种先进后出的数据结构,也就是说它们的执行顺序与注册(添加)顺序相反,当执行完所有清理函数后,线程终止。

#include <pthread.h>
void pthread_cleanup_push(void (*routine)(void *), void *arg);
void pthread_cleanup_pop(int execute);

**注意:尽管上面我们将 pthread_cleanup_push()和 pthread_cleanup_pop()称之为函数,但它们是通过宏来实现,

可展开为分别由{和}所包裹的语句序列,push和pop必须成对出现,不然会报错, eg: **

#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<sys/types.h>
#include<string.h>
#include<pthread.h>
void cleanup(void *arg)
{
  printf("cleanup: %s\n", (char *)arg);
}
void *thread_func(void *arg)
{
  pthread_cleanup_push(cleanup, "第一次调用");  // {
  pthread_cleanup_push(cleanup, "第二次调用");  // {
  pthread_cleanup_push(cleanup, "第三次调用");  // {
  pthread_cleanup_pop(0);             // }
  printf("~~~~~~~~~~~~~~~~~~~~\n");
  sleep(2);
  pthread_exit((void *)0);
  //pthread_cleanup_pop(0);
  pthread_cleanup_pop(0);    // }
  pthread_cleanup_pop(0);    // }
}
int main()
{
  int ret = 0;
  pthread_t t;
  void *tret;
  ret = pthread_create(&t, NULL, thread_func, NULL);
  if (ret)
  {
    fprintf(stderr, "pthread_create error: %s\n", strerror(ret));
    exit(-1);
  }
  // 等待线程结束
  ret = pthread_join(t, &tret);
  if (ret)
  {
    fprintf(stderr, "pthread_join error: %s\n", strerror(ret));
    exit(-1);
  }
  printf("新线程终止, code=%ld\n", (long)tret);
  exit(0);
}

8. 线程属性

前面所讲的pthread_create有个参数attr就是线程属性。

8.1 属性初始化

#include <pthread.h>
int pthread_attr_init(pthread_attr_t *attr);     // 属性初始化
int pthread_attr_destroy(pthread_attr_t *attr);  // 释放属性

8.2 线程栈属性

#include <pthread.h>
int pthread_attr_setstack(pthread_attr_t *attr, void *stackaddr, size_t stacksize);
int pthread_attr_getstack(const pthread_attr_t *attr, void **stackaddr, size_t *stacksize);
int pthread_attr_setstacksize(pthread_attr_t *attr, size_t stacksize);
int pthread_attr_getstacksize(const pthread_attr_t *attr, size_t *stacksize);
int pthread_attr_setstackaddr(pthread_attr_t *attr, void *stackaddr);
int pthread_attr_getstackaddr(const pthread_attr_t *attr, void **stackaddr);

8.3 分离状态属性

可以在创建线程的时候就设定好分离线程,不需要后面调用pthread_detach来分离

#include <pthread.h>
int pthread_attr_setdetachstate(pthread_attr_t *attr, int detachstate);
int pthread_attr_getdetachstate(const pthread_attr_t *attr, int *detachstate);

detachstate:

  • PTHREAD_CREATE_DETACHED:新建线程一开始运行便处于分离状态,以分离状态启动线程,无法被其它线程调用 pthread_join()回收,线程结束后由操作系统收回其所占用的资源;
  • PTHREAD_CREATE_JOINABLE:这是 detachstate 线程属性的默认值,正常启动线程,可以被其它线程获取终止状态信息。


目录
相关文章
|
Linux
linuxC线程同步问题
linuxC线程同步问题
89 0
|
7天前
|
Java
实现Java多线程中的线程间通信
实现Java多线程中的线程间通信
|
5天前
|
设计模式 安全 Java
Java面试题:设计模式如单例模式、工厂模式、观察者模式等在多线程环境下线程安全问题,Java内存模型定义了线程如何与内存交互,包括原子性、可见性、有序性,并发框架提供了更高层次的并发任务处理能力
Java面试题:设计模式如单例模式、工厂模式、观察者模式等在多线程环境下线程安全问题,Java内存模型定义了线程如何与内存交互,包括原子性、可见性、有序性,并发框架提供了更高层次的并发任务处理能力
18 1
|
5天前
|
设计模式 存储 安全
Java面试题:设计一个线程安全的单例类并解释其内存占用情况?使用Java多线程工具类实现一个高效的线程池,并解释其背后的原理。结合观察者模式与Java并发框架,设计一个可扩展的事件处理系统
Java面试题:设计一个线程安全的单例类并解释其内存占用情况?使用Java多线程工具类实现一个高效的线程池,并解释其背后的原理。结合观察者模式与Java并发框架,设计一个可扩展的事件处理系统
14 1
|
8天前
|
Java
实现Java多线程中的线程间通信
实现Java多线程中的线程间通信
|
3天前
|
缓存 Linux 编译器
【Linux】多线程——线程概念|进程VS线程|线程控制(下)
【Linux】多线程——线程概念|进程VS线程|线程控制(下)
11 0
|
3天前
|
存储 Linux 调度
【Linux】多线程——线程概念|进程VS线程|线程控制(上)
【Linux】多线程——线程概念|进程VS线程|线程控制(上)
14 0
|
5天前
|
设计模式 并行计算 安全
Java面试题:如何使用设计模式优化多线程环境下的资源管理?Java内存模型与并发工具类的协同工作,描述ForkJoinPool的工作机制,并解释其在并行计算中的优势。如何根据任务特性调整线程池参数
Java面试题:如何使用设计模式优化多线程环境下的资源管理?Java内存模型与并发工具类的协同工作,描述ForkJoinPool的工作机制,并解释其在并行计算中的优势。如何根据任务特性调整线程池参数
10 0
|
5天前
|
设计模式 安全 NoSQL
Java面试题:结合单例模式与Java内存管理,设计一个线程安全的单例类?分析Java多线程工具类ExecutorService与Java并发工具包中的工具类,设计一个Java并发框架的分布式锁实现
Java面试题:结合单例模式与Java内存管理,设计一个线程安全的单例类?分析Java多线程工具类ExecutorService与Java并发工具包中的工具类,设计一个Java并发框架的分布式锁实现
13 0
|
5天前
|
存储 安全 Java
Java面试题:假设你正在开发一个Java后端服务,该服务需要处理高并发的用户请求,并且对内存使用效率有严格的要求,在多线程环境下,如何确保共享资源的线程安全?
Java面试题:假设你正在开发一个Java后端服务,该服务需要处理高并发的用户请求,并且对内存使用效率有严格的要求,在多线程环境下,如何确保共享资源的线程安全?
12 0