关于C语言中线程同步的方式

C语言中线程同步的方式

  • 线程同步
  • 互斥锁
  • 读写锁
  • 条件变量
  • 信号量

线程同步

在多线程环境中,线程之间由于竞争共享资源(临界资源)容易引起数据不一致的问题。一般采用互斥锁(互斥信号量)解决,保证只有一个线程进入临界区

互斥锁

使用步骤

  1. 初始化互斥锁
  • 静态创建
    /**
     * 使用宏定义以及初始化锁
     */
    pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
    
  • 动态创建
    /**
     * 参数:
     *   1:互斥锁
     *   2:互斥锁属性
     */
    int pthread_mutex_init(pthread_mutex_t * __restrict,
    	const pthread_mutexattr_t * _Nullable __restrict);
    
  1. 加锁以及解锁
  • 加锁(阻塞)
    /**
     * 参数:
     *   互斥锁变量
     * 返回值:
     *   是否成功
     */ 
    int pthread_mutex_lock(pthread_mutex_t *);
    
  • 尝试加锁(非阻塞)
    /**
     * 参数:
     *   互斥锁变量
     * 返回值:
     *   成功返回0
     *   失败返回错误码
     */ 
     int pthread_mutex_trylock(pthread_mutex_t *); 
    
  • 解锁
    /**
     * 参数:
     *   互斥锁变量
     * 返回值:
     *   成功返回0
     *   失败返回错误码
     */ 
    int pthread_mutex_lock(pthread_mutex_t *);
    
  1. 销毁锁
    /**
     * 参数:
     *   互斥锁变量
     * 返回值:
     *   成功返回0
     *   失败返回错误码
     */ 
    int pthread_mutex_destroy(pthread_mutex_t *);
    

读写锁

为了解决性能问题,引入读写锁,特点是:读共享,写独享,写优先级高,读写之间也是互斥的。适合读线程较多的场景。
注意:在A线程加锁状态下,当B线程请求读锁,然后C线程请求写锁时,在A释放锁的情况下,C请求的写锁先获取到。

读写锁使用步骤与互斥锁基本相同,函数原型如下。

//初始化
pthread_rwlock_t mutex = PTHREAD_RWLOCK_INITIALIZER;
//或者
int pthread_rwlock_init(pthread_rwlock_t * __restrict,
		const pthread_rwlockattr_t * _Nullable __restrict);

//加锁(读写)
int pthread_rwlock_rdlock(pthread_rwlock_t *);
int pthread_rwlock_tryrdlock(pthread_rwlock_t *)

int pthread_rwlock_wrlock(pthread_rwlock_t *);
int pthread_rwlock_trywrlock(pthread_rwlock_t *)//解锁
pthread_rwlock_unlock()//释放锁
int pthread_rwlock_destroy(pthread_rwlock_t * )

条件变量

条件变量本质不是锁,通常与互斥锁配合使用。
当条件不满足时,阻塞线程。
当条件满足时,通知线程解除阻塞。

区别于Java

1. Object中wait()、notify()、notifyAll() 是进程间通信(同步)的方式,且必须在synchronized中使用。
2. Java并发包下condition.await()、condition.signal() 也是用于线程通信的。

使用方式

  1. 初始化条件变量
     pthread_cond_t cond=PTHREAD_COND_INITIALIZER;
     //或者
     int pthread_cond_init(
    	pthread_cond_t * __restrict,
    	const pthread_condattr_t * _Nullable __restrict)
    
  2. 条件不满足阻塞
    /**
     * 阻塞并且释放锁
     * 当接收到信号加锁继续执行
     * 
     * 参数:
     *   1:条件变量
     *   2:锁
     * 返回值:
     *   是否成功
     */
    int pthread_cond_wait(pthread_cond_t * __restrict,
    	pthread_mutex_t * __restrict)
    
  3. 条件满足唤醒
    /**
     * 唤醒阻塞的线程
     * 参数:
     *   条件变量
     * 返回值:
     *   是否成功
     */
    int pthread_cond_signal(pthread_cond_t *)
    
  4. 释放条件变量
    int pthread_cond_destroy(pthread_cond_t *);
    

信号量

信号量是用来标识可同时使用的共享资源的个数。

使用方式

  1. 初始化
    /**
     * 参数:
     *   1:sem_t变量
     *   2:0线程同步,1进程同步
     *   3:资源数
     * 返回值:
     *   是否成功
     */
    int sem_init(sem_t *, int, unsigned int)
    
  2. 条件判断
    当条件不满足时,阻塞线程,信号量自减。
  • 阻塞
    int sem_wait(sem_t *)
    
  • 非阻塞
    int sem_trywait(sem_t *)
    
  1. 唤醒
    当条件满足时,唤起所有阻塞的线程,信号量自增,同时加锁。
    所有阻塞线程同时抢占CPU,抢到CPU时间片的执行。
    ❗❗ 此时,仍需要条件判断。
    int sem_post(sem_t *)
    
  2. 释放信号量
    int sem_destroy(sem_t *)
    

你可能感兴趣的:(Unix\Linux,C\C++,线程,多线程,c语言,内存结构)