UNXI线程及线程间同步方式

线程的资源

  • 共享:代码段、堆、全局变量和静态变量(.dss和.data)、打开的文件描述符、信号的处理器、进程的当前目录、进程用户ID与用户组ID
  • 独享:栈、信号屏蔽集、errno值,寄存器(物理寄存器的副本)、线程ID、线程的调度优先级、线程的私有数据

同一个进程的多个线程之间共享了很多资源,对这些资源的访问需要同步,防止出现不一致的情况

线程基本操作

线程标识

线程的标识为pthread_t类型,不能把它简单的当做一个整数处理,因为有些实现把它实现为一个结构。(进程的标识类型为pid_t,是一个非负整数)

#include <pthread.h>
int pthread_equal(pthread_t tid1, pthread_t tid2);
pthread_t pthread_self(void);

线程创建

#include <pthread.h>
int pthread_create(pthread_t *restrict tidp, const pthread_attr_t *restrict attr, void *(*start_rtn)(void *), void *restrict arg);
  • 线程创建时并不能保证哪个线程先运行,是新创建的线程还是调用线程。
  • 如果要先start_rtn函数传递的参数不止一个,需要把这些参数放入一个结构,然后把该结构的地址作为arg参数传入。
  • 虽然每个线程有独享的errno变量,但是pthread的函数通常通过函数返回值返回错误码。

线程终止

1.终止整个进程:在线程中调用exit,_Exit,_exit
2.终止单个线程

  • 从启动例程中就返回
  • 被同一个进程中的其他线程取消(pthread_cancel)
  • 线程调用pthread_exit
#include <pthrad.h>
void pthread_exit(void *rval_ptr);//rval_ptr指向的内存不应该是线程独享的
int pthread_join(pthread_t thread, void **rval_ptr);
int pthread_cancel(pthread_t tid);
void pthread_cleanup_push(void (*rtn)(void*), void * arg);
void pthread_cleanup_pop(int execute);
int pthread_detach(pthread_t tid);

线程间同步

对一个内存单元中存储的值进行修改分为三步:从内存单元读入寄存器,在内存器中对变量做修改,把新的值写回内存单元。如果这三个步骤不是原子操作,就可能会出现竞争(多个线程观察到的数据不一致)。

互斥量

  • 互斥量是pthread_mutex_t数据类型,相当于一把锁,同时只能有一个线程获得锁
  • 使用前必须初始化,动态分配的互斥量释放内存之前必须销毁
#include <pthread.h>
int pthread_mutex_init(pthread_mutex_t *restrict mutex, const pthread_mutexattr_t *restrict attr);//互斥量使用前必须初始化
pthread_mutex_t mt = PTHREAD_MUTEX_INITIALIZER;//这种初始化方式只适用于静态分配的互斥量
int pthread_mutex_destroy(pthread_mutex_t *mutex); //如果动态分配互斥量,在释放内存前要destroy
int pthread_mutex_lock(pthread_mutex_t *mutex);
int pthread_mutex_trylock(pthread_mutex_t *mutex); //如果不能锁住互斥量,返回EBUSY
int pthread_mutex_unlock(pthread_mutex_t *mutex);
  • 指定最长阻塞时间
#include <pthread.h>
#include <time.h>
int pthread_mutex_timedlock(pthread_mutex_t *restric mutex, const struct timespec *restric tsptr);

读写锁

  • 读写锁是pthread_rwlock_t数据类型
  • 有三个状态:写模式加锁,读模式加锁,不加锁
  • 一次只能有一个线程占用写模式的读写锁,多个线程可以同时占有读模式的读写锁
  • 适合于对数据结构的读次数远大于写次数的场景
  • 使用前必须初始化,释放内存之前必须销毁
#include <pthread.h>
int pthread_rwlock_init(pthread_rwlock_t *restrict rwlock, const pthread_rwlockattr_t *restrict attr);
pthread_rwlock_t rwlock = PTHREAD_RWLOCK_INITIALIZER;//这种初始化方式只适用于静态分配的读写锁
int pthread_rwlock_destroy(pthread_rwlock_t *rwlock);//必须销毁
int pthread_rwlock_rdlock(pthread_rwlock_t *rwlock);
int pthread_rwlock_wrlock(pthread_rwlock_t *rwlock);
int pthread_rwlock_unlock(pthread_rwlock_t *rwlock);
int pthread_rwlock_trywrlock(pthread_rwlock_t *rwlock);
int pthread_rwlock_tryrdlock(pthread_rwlock_t *rwlock);
int pthread_rwlock_timedrdlock(pthread_rwlock_t *restrict rwlock, const struct timespec *restrict tsptr);
int pthread_rwlock_timedwrlock(pthread_rwlock_t *restrict rwlock, const struct timespec *restrict tsptr);

条件变量

  • 条件变量用于一个线程向一个或者多个线程发送条件改变的信号
  • 条件变量要和互斥量一同使用。线程在改变条件之前要先锁住互斥量,改变完条件之后发送信号并且把互斥量解锁。其他线程接收到通知被唤醒后,首先要尝试锁定互斥量,只有锁定了互斥量的线程可以检查条件。因此对条件的修改和检查是无竞争的,因为同时只有一个线程对条件进行操作。
    -条件变量是pthread_cond_t类型
#include <pthread.h>
int pthread_cond_init(pthread_cond_t *restrict cond, const pthread_condattr_t *restrict attr);
pthread_cond_t condv = PTHREAD_COND_INITIALIZER; //只能用于初始化静态分配的条件变量
int pthread_cond_destroy(pthread_cond_t *cond);
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 tsptr);  //相对时间
int pthread_cond_signal(pthread_cond_t *cond);  //至少能唤醒一个等待该条件的线程
int pthread_cond_broadcast(pthread_cond_t *cond); //唤醒所有等待该条件的线程

https://www.cnblogs.com/harlanc/p/8596211.html

自旋锁

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值