Linux系统编程学习之《线程》

今天来总结一下Linux下的线程方面知识:

和进程相似,线程也有系统内的标识符,它的类型是pthread_t(进程是pid_t)

线程标识符只在同一进程内有效,不同进程之间可以有相同的线程标识符


1.线程标识符

我们先来看看有关线程标识符的函数

/*
 * #include <pthread.h>
 * int pthread_equal(pthread_t tid1,pthread_t tid2);
 * 比较tid1和tid2两个线程是否是同一个线程(不同进程可有相同线程ID)
 * 是统一个返回非0,不是返回0
 * ---------------------------------------------------
 * pthread_t pthread_self(void);
 * 返回线程的ID
 */

2.创建线程

Linux下创建线程比较简单,只要调用一个函数就可以了

/*
 * #include <pthread.h>
 * int pthread_create(pthread_t * restrict tidp,const pthread_attr_t * restrict attr,
 *             void * (*start_rtn)(void),void * restrict arg);
 * tidp:保存新线程ID的指针
 * attr:创建的线程的属性,NULL为默认属性
 * (*start_rtn)(void):线程启动要要执行的函数,声明格式是:void * funcname(void * arg);
 * arg:线程执行函数的参数,NULL为不传参数
 */

3.终止线程

终止线程有三种终止方式:1.线程从启动例程中返回   2.线程被同一进程中的其他线程取消   3.线程自己调用pthread_exit

/*
 * #include <pthread.h>
 * void pthread_exit(void * rval_ptr);
 * 线程自己调用,终止线程运行,直接返回,返回码保存在rval_ptr中
 * --------------------------------------
 * int pthread_join(pthread_t thread,void ** rval_ptr);
 * 同一进程中的其他线程可以调用此函数,等待指定线程结束,并获取它的返回码
 * 等待过程将阻塞调用此函数的线程
 * --------------------------------------
 * int pthread_cancel(pthread_t tid);
 * 成功返回0,出错返回错误编号
 * 该函数用于线程提出请求终止同一进程中的其他线程,不过被请求线程可忽略此请求
 */

4.清理线程

我们知道,进程退出是可用atexit函数注册一些清理处理的函数,线程也一样可以调用一些清理函数

/*
 * #include <pthread.h>
 * void pthread_cleanup_push(void (*rtn)(void *),void * arg);
 * (*rtn)(void *):清理处理函数,定义格式:void funcname(void * arg);
 * arg:传给清理处理函数的参数
 * -----------------------------------
 * void pthread_cleanup_pop(int execute);
 * execute:非0则执行清理函数,0则不执行
 * -----------------------------------
 * 上述两个函数要在作用域{}内配对使用,否则可能会出错
 */

5.分离线程

线程有一个分离状态,使得调用pthread_join函数无法等待到它的终止状态,线程的分离状态可以在创建时确立,也可以调用函数

/*
 * #include <pthread.h>
 * int pthread_detach(pthread_t tid);
 * 成功返回0,出错返回错误编号
 * 该函数使线程进入分离状态
 */

6.线程同步之互斥量(锁)

当有多个线程同时访问同一个变量的时候,就可能会出现数据读写不同步的问题,这就需要我们设置线程的同步机制

作为同步机制,最重要的当然就是锁了,Linux中的锁变量类型是pthread_mutex_init

/*
 * #include <pthread.h>
 * int pthread_mutex_init(pthread_mutex_t * restrict mutex,const pthread_mutexattr_t * restrict attr);
 * ----------------------------------------
 * mutex:锁变量
 * attr:锁的属性,NULL为默认属性
 * ----------------------------------------
 * int pthread_mutex_destroy(pthread_mutex_t * mutex);
 * ----------------------------------------
 * 要销毁的锁变量
 * ----------------------------------------
 * 两个函数成功返回0,出错返回错误编号
 * ----------------------------------------
 * 锁的变量类型是pthread_mutex_t,要使用锁之前,先要对其进行初始化
 * 可以把它设置为常量PTHREAD_MUTEX_INITALIZER(只对静态分配的互斥锁有效)
 * 其他的就要调用pthread_mutex_init函数
 * 如果是动态分配的互斥锁(如调用malloc函数)
 * 则在释放内存前需要调用pthread_mutex_destroy函数销毁
 * ----------------------------------------
 */

7.线程同步之互斥量(锁)加锁

在互斥锁初始化后,我们需要调用一些函数才可以实现真正的加锁行为

/*
 * #include <pthread.h>
 * int pthread_mutex_lock(pthread_mutex_t * mutex);
 * int pthread_mutex_trylock(pthread_mutex_t * mutex);
 * int pthread_mutex_unlock(pthread_mutex_t * mutex);
 * ---------------------------------
 * 三个函数成功返回0,出错返回错误编号
 * mutex是欲操作的锁变量
 * pthread_mutex_lock对于mutex未加锁,则直接加锁进入下一步骤
 * 如果mutex已被加锁,则线程会被阻塞,一致等待锁被释放了才进入锁
 * pthread_mutex_trylock对于mutex未枷锁,则直接加锁进入下一步骤,返回0
 * 如果mutex已被加锁,则线程不会被阻塞,加锁失败,返回EBUSY
 * 无论哪种加锁方式,释放锁同一调用pthread_mutex_unlock函数
 * ---------------------------------
 */

8.线程同步之读写锁

除了上述的互斥锁外,Linux还支持读写锁,读写锁也程共享-独占锁;

当读写锁以读模式锁住时,它是以共享模式锁住的;当它以写模式锁住时,它是以独占模式锁住的

读写锁的变量类型是pthread_rwlock_t,读写锁只可以用调用函数初始化方式初始化锁

/*
 * #include <pthread.h>
 * int pthread_rwlock_init(pthread_rwlock_t * restrict rwlock,const pthread_rwlockattr_t * restrict attr);
 * ----------------------------------------
 * rwlock:读写锁变量
 * attr:读写锁属性,NULL为默认属性
 * ----------------------------------------
 * int pthread_rwlock_destroy(pthread_rwlock_t * rwlock); //rwlock为欲销毁的读写锁变量
 * ----------------------------------------
 * 两个函数成功返回0,粗错返回错误编号
 */

9.线程同步之读写锁加锁

了解了如何创建、初始、销毁读写锁后,现在就要了解如何对对写锁进行加锁

正如前面所说,读写锁有两种加锁方式,读锁加锁或写锁加锁

/*
 * #include <pthread.h>
 * int pthread_rwlock_rdlock(pthread_rwlock_t * rwlock);  //加读锁
 * int pthread_rwlock_wrlock(pthread_rwlock_t * rwlock);  //加写锁
 * int pthread_rwlock_unlock(pthread_rwlock_t * rwlock);  //解除锁
 * 所有函数:成功返回0,出错返回错误编号
 * ------------------------------------------
 * 加读锁时,如果没有被加写锁,则允许进入,否则阻塞
 * 加写锁时,要当前锁没有任何锁状态才进入,否则阻塞等待
 * 读锁写锁使用完毕后都要调用unlock函数解除锁状态
 * ------------------------------------------
 * int pthread_rwlock_tryrdlock(pthread_rwlock_t * rwlock);  //尝试加读锁
 * int pthread_rwlock_tryrwlock(pthread_rwlock_t * rwlock);  //尝试加写锁
 * ------------------------------------------
 * 如果成功获取锁,则进入,函数返回0
 * 否则,返回出错EBUSY,但并不阻塞等待
 */

10.线程同步之条件变量

条件变量是线程同步的另一种同步机制。条件变量与互斥量一起使用时,允许线程以无竞争的方式等待特定的条件发生

条件变量的数据类型是pthread_cond_t,有两种初始化方式

一种把PTHREAD_COND_INITIALIZER赋给静态分配的条件变量,如果是动态分配的,则调用pthread_cond_init哈数进行初始化

/*
 * #include <pthread.h>
 * int pthread_cond_init(pthread_cond_t * restrict cond,pthread_condaddr_t * restrict attr);
 * int pthread_cond_destroy(pthread_cond_t * cond); //cond为条件变量
 * 两个函数:成功返回0,出错返回错误编号
 * 在init函数中,如果要传递NULL给attr,则创建默认的条件变量
 */

11.线程同步之条件变量的使用

在初始化好条件变量后,我们现在要使用它了,使用的方法是调用如下函数:

/*
 * #include <pthread.h>
 * int pthread_cond_wait(pthread_cond_t * restrict cond,pthread_mutex_t * restrict mutex);  //对等待事件出现,再加互斥锁
 * int pthread_cond_timewait(pthread_cond_t * restrict cond,
 * pthread_mutex_t * restrict mutex,const struct timespec * restrict timeout);  //跟上面函数类似,不过等待绝对时间(即现在时间+需等待时间)
 * 两个函数成功返回0,出错返回错误编号
 * -------------------------------------------
 * int pthread_cond_signal(pthread_cond_t * cond);  //唤醒等待该条件变量的某个线程
 * int pthread_cond_broadcast(pthread_cond_t * cond);  //唤醒等待该条件变量的全部线程
 * -------------------------------------------
 */


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值