c-互斥锁 读写锁 信号量

线程间同步

  • 互斥锁
  • 读写锁
  • 信号量

进程间同步

  • 信号量
  • 互斥量
  • 文件锁

互斥锁

pthread_mutext_t mutext;

特点:

  • 阻塞,串行地访问共享数据
# include <stdio.h>
# include <pthread.h>
 
pthread_mutex_t mute;
int value = 0;
void *fun(void *arg){
    //上锁,函数是阻塞的
    pthread_mutex_lock(&mute);
    printf("now is %d and old value is %d \n",*((int *)arg), value);
    ++value;
    printf("now is %d and new value is %d \n",*((int *)arg), value);
    //解锁
    pthread_mutex_unlock(&mute);
}
int main(){
 
    pthread_t threads[5];
    int thread_id[5];
    //创建锁,相当于new一个对象
    pthread_mutex_init(&mute, NULL);
    for(int i=0; i<5; ++i){
        thread_id[i] = i;
        pthread_create(&threads[i], NULL, fun, (void *)&thread_id[i]);
    }
    for(int i=0; i<5; ++i)
        int rc = pthread_join(threads[i], NULL);
    //释放互斥锁
    pthread_mutex_destroy(&mute);
    return 0;
}

读写锁

使用场景: 读的情况比写的情况多.

特性

读共享 - 并行处理
写独占 - 写的优先级高
场景:
线程A持有读锁, 然后线程B请求写锁,然后线程C请求读锁
result: B阻塞, C阻塞,然后 B获得锁, 最后C才获得锁
线程A持有写锁, 然后线程B请求读锁, 然后线程C请求写锁
result 等到A释放锁以后, C是写锁, 优先级高 所以C先获得锁, 最后才是B

声明:

Int pthread_rwlock_init(pthread_rwlock_t *restrict rwlock, //初始化读写锁
const pthread_rwlockattr_t *restrict attr);

Int pthread_rwlock_destroy(pthread_rwlock_t *rwlock);	//销毁读写锁

Int pthread_rwlock_rdlock(pthread_rwlock_t *rwlock);	//加读锁
Int pthread_rwlock_tryrdlock(pthread_rwlock_t *rwlock);	//尝试加读锁

Int pthread_rwlock_wrlock(pthread_rwlock_t *rwlock); //加写锁
Int pthread_rwlock_trywrlock(pthread_rwlock_t *rwlock); //尝试加写锁

Int pthread_rwlock_unlock(pthread_rwlock_t *rwlock);	//解锁

DEMO

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <pthread.h>


int number = 0;
//创建读写锁
pthread_rwlock_t lock;

void* write_func(void* arg){

    while (1)
    {
        //加写锁
        pthread_rwlock_wrlock(&lock);
        number++;
        printf("write:thread %lu,  number= %d \n", pthread_self(), number);
        //解锁
        pthread_rwlock_unlock(&lock);
        usleep(500);
    }

    return NULL;
}

void* read_func(void* arg){
    while (1)
    {
        //加读锁
        pthread_rwlock_rdlock(&lock);
        printf("read:thread %lu,  number= %d \n", pthread_self(), number);
        pthread_rwlock_unlock(&lock);
        usleep(500);
    }
    return NULL;
}

int main(){

    pthread_t p[8];
    //初始化读写锁
    pthread_rwlock_init(&lock, NULL);

    //创建3个写线程
    for (int i = 0; i < 3; i++)
    {
        pthread_create(&p[i], NULL, write_func, NULL);
    }
    
    //创建5个读线程
    for (int i = 3; i < 8; i++)
    {
        pthread_create(&p[i], NULL, read_func, NULL);
        
    }

    //阻塞回收子线程资源的tcb
    for (int i = 0; i < 8; i++)
    {
        pthread_join(p[i], NULL);
    }

    //释放读写锁
    pthread_rwlock_destroy(&lock);
    return 0;
}

条件变量

  • 本质不是一把锁, 但是能够阻塞函数.
  • 使用条件变量 + 互斥量
  • 互斥量: 保护一块共享内存
  • 条件变量: 引起阻塞
// 初始化一个条件变量 
int pthread_cond_init(pthread_cond_t * cond, const pthread_condattr_t * attr);
// 销毁一个条件变量
int pthread_cond_destroy(pthread_cond_t *cond);
// 阻塞等待一个条件变量
// 阻塞线程,将已上锁的mutex解锁,该函数解除阻塞会加互斥锁. 
int pthread_cond_wait(pthread_cond_t *restrict cond, pthread_mutex_t *restrict mutex);
// 限时阻塞等待一个条件变量
int pthread_cond_timedwait(pthread_cond_t *cond,pthread_mutex_t *mutex, const struct timespec *restrict abstime);
//唤醒一个阻塞在条件变量上的线程
int pthread_cond_signal(pthread_cond_t *cond);
//唤醒全部阻塞在条件变量上的线程
int pthread_cond_broadcast(pthread_cond_t *cond);

DEMO

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <pthread.h>

//创建节点结构
typedef struct node{
    int data;
    struct node* next;
}Node;

//永远指向链表头部的指针
Node* head = NULL;

//线程同步 需要一个互斥锁
pthread_mutex_t mutex;
//阻塞线程 -- 条件变量类型的 变量
pthread_cond_t cond;
//生产者
void* producer(void* arg){
    while(1){
        //创建一个链表节点
        Node* pnew = (Node*)malloc(sizeof(Node));
        //节点的初始化
        pnew->data = rand()%1000; //0-999
        
        //使用互斥锁保护共享数据
        pthread_mutex_lock(&mutex);
        //指针域
        pnew->next = head;
        head = pnew;
        printf("produce: %ul, %d\n", pthread_self(), pnew->data);
        pthread_mutex_unlock(&mutex);

        //通知阻塞的消费者线程, 解除阻塞
        pthread_cond_signal(&cond);

        sleep(rand() % 3);
    }
    return NULL;
}

void* costumer(void* arg){
    while(1)
    {
        //使用互斥锁保护共享数据
        pthread_mutex_lock(&mutex);
        //消费前判断链表是否为空
        if(head == NULL) 
        {
            //线程阻塞
            //	该函数会对互斥锁解锁.解除mutex阻塞之后,
            // 	等待对方完成后, 调用 pthread_cond_signal(&cond); 
            // 	会在第一时间获得锁,对 mutex 互斥锁进行枷锁操作
            pthread_cond_wait(&cond, &mutex);
            //
            
        }
        //链表不为空,删掉一个头结点
        Node* pdel = head;
        head = head->next;
        printf("---custumer: %ul, %d\n", pthread_self(), pdel->data);
        free(pdel);
        pthread_mutex_unlock(&mutex);
        
    }
    return NULL;
}

int main(){

    pthread_t p1, p2;
    //初始化
    pthread_mutex_init(&mutex, NULL);
    pthread_cond_init(&cond, NULL);

    //创建生产者线程
    pthread_create(&p1, NULL, producer, NULL);
    //创建消费者线程
    pthread_create(&p2, NULL, costumer, NULL);

    //阻塞回收子线程
    pthread_join(p1, NULL);
    pthread_join(p2, NULL);

    //回收
    pthread_mutex_destroy(&mutex);
    pthread_cond_destroy(&cond);

    return 0;
}

信号量

高级的互斥锁

// 成功返回0,失败返回-1;
// 参数sem:表示指向信号结构的指针。
// 参数pshared:不是0 的时候该信号量在进程间共享,否则只能在当前进程的所有线程间共享。
// 参数value:信号量的初始值。允许多少个线程or进程同时共享
int sem_init(sem_t * sem, int pshared, unsigned int value);//初始化信号量

int sem_destroy(sem_t *sem); //销毁信号量。
int sem_wait(sem_t *sem); 	//信号量减一操作,减少个资源数, 有线程申请资源
int sem_trywait(sem_t *sem);	//sem==0 加锁失败,不阻塞,直接返回
int sem_timedwait(setm_t *sem);	//限时尝试加锁
int sem_post(sem_t *sem); 	//信号量加一操作,增加资源数, 有线程释放资源

在这里插入图片描述

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <pthread.h>
#include <semaphore.h>

//创建节点结构
typedef struct node{
    int data;
    struct node* next;
}Node;

//永远指向链表头部的指针
Node* head = NULL;

//创建两个信号量
sem_t produce_sem;
sem_t custom_sem;

//生产者
void* producer(void* arg){
    while(1){
        //创建一个链表节点
        Node* pnew = (Node*)malloc(sizeof(Node));
        //节点的初始化
        pnew->data = rand()%1000; //0-999
        
        sem_wait(&produce_sem);     //produce_sem--
        //指针域
        pnew->next = head;
        head = pnew;
        printf("produce: %lu, %d\n", pthread_self(), pnew->data);
        
        sem_post(&custom_sem);  //custom_sem++

        sleep(rand() % 3);
    }
    return NULL;
}

void* costumer(void* arg){
    while(1)
    {
        sem_wait(&custom_sem);     //custom_sem--
        //链表不为空,删掉一个头结点
        Node* pdel = head;
        head = head->next;
        printf("---custumer: %lu, %d\n", pthread_self(), pdel->data);
        free(pdel);

        sem_post(&produce_sem);
        sleep(rand()%5);
        
        
    }
    return NULL;
}

int main(){

    pthread_t p1, p2;
    //初始化
    sem_init(&produce_sem, 0, 4);   //初始化线程信号量
    sem_init(&custom_sem, 0, 0);    //初始化消费者线程信号量

    //创建生产者线程
    pthread_create(&p1, NULL, producer, NULL);
    //创建消费者线程
    pthread_create(&p2, NULL, costumer, NULL);

    //阻塞回收子线程
    pthread_join(p1, NULL);
    pthread_join(p2, NULL);

    //回收
    sem_destroy(&produce_sem);
    sem_destroy(&custom_sem);

    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

北京时光

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值