线程同步

线程同步

数据不一致的主要原因就是多个线程指令交叉执行

线程同步_第1张图片
image.png
互斥量

互斥量可以保证先后执行,保证了关键操作的原子性

操作系统提供了互斥量的API:pthread_mutex_t

#include 
#include 
#include 
#include 
#include 

// 定义一个互斥量
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;

// 临界资源
int num = 0;

// 生产者
void *producer(void*){
    int times = 100000000;
    while(times --){
        // 给互斥量加锁
        pthread_mutex_lock(&mutex);
        num += 1;
        // 给互斥量解锁
        pthread_mutex_unlock(&mutex);
    }
}

// 消费者
void *comsumer(void*){
    int times = 100000000;
    while(times --){
        pthread_mutex_lock(&mutex);
        num -= 1;
        pthread_mutex_unlock(&mutex);
    }
}


int main(){
    printf("Start in main function.");
    pthread_t thread1, thread2;
    // 创建一个线程
    // 线程标识符指针  线程属性  运行函数指针  运行函数参数
    pthread_create(&thread1, NULL, &producer, NULL);
    pthread_create(&thread2, NULL, &comsumer, NULL);
    // 等待一个线程的结束
    // 线程标识符  等待线程的返回值
    pthread_join(thread1, NULL);
    pthread_join(thread2, NULL);
    printf("Print in main function: num = %d\n", num);
    return 0;
}
自旋锁

自旋锁和互斥量思想没什么差别

自旋锁会反复检查锁是否可用,并不会让出CPU,其在死循环等待锁被释放,避免了进程后线程上下文切换的开销,但如果加锁时间比较持久,CPU会一直处于空转状态

操作系统提供了自旋锁API:pthread_spinlock_t

#include 
#include 
#include 
#include 
#include 

// 声明一个自旋锁
pthread_spinlock_t spin_lock;

int num = 0;

void *producer(void*){
    int times = 10000000;
    while(times --){
        // 给自旋锁加锁
        pthread_spin_lock(&spin_lock);
        num += 1;
        // 释放自旋锁
        pthread_spin_unlock(&spin_lock);
    }
}

void *comsumer(void*){
    int times = 10000000;
    while(times --){
        pthread_spin_lock(&spin_lock);
        num -= 1;
        pthread_spin_unlock(&spin_lock);
    }
}


int main(){
    printf("Start in main function.\n");
    // 初始化自旋锁  
    // 自旋锁标识符指针 自旋锁的共享范围(仅初始化本自旋锁的线程所在的进程内的线程才能够使用该自旋锁)
    pthread_spin_init(&spin_lock, PTHREAD_PROCESS_PRIVATE);
    pthread_t thread1, thread2;
    pthread_create(&thread1, NULL, &producer, NULL);
    pthread_create(&thread2, NULL, &comsumer, NULL);
    pthread_join(thread1, NULL);
    pthread_join(thread2, NULL);
    printf("Print in main function: num = %d\n", num);
    return 0;
}
读写锁

临界资源多读少写,读取的时候并不会改变临界资源的值,是一种特殊的自旋锁,允许多个读者同时访问资源,但对于写操作时互斥的

操作系统提供了读写锁API:pthread_rwlock_t pthread_rwlock_rdlock pthread_rwlock_wrlock

#include 
#include 
#include 
#include 
#include 

int num = 0;

// 定义读写锁
pthread_rwlock_t rwlock = PTHREAD_RWLOCK_INITIALIZER;

void *reader(void*){
    int times = 10000000;
    while(times --){
        // 加读锁
        pthread_rwlock_rdlock(&rwlock);        
        if (times % 1000 == 0){
            printf("print num in reader: num = %d\n", num);
            usleep(10);
        }
        // 释放读锁
        pthread_rwlock_unlock(&rwlock);
    }
}

void *writer(void*){
    int times = 10000000;
    while(times --){
        // 加写锁
        pthread_rwlock_wrlock(&rwlock);
        num += 1;
        // 释放写锁
        pthread_rwlock_unlock(&rwlock);
    }
}


int main(){
    printf("Start in main function.\n");
    pthread_t thread1, thread2, thread3;
    pthread_create(&thread1, NULL, &reader, NULL);
    pthread_create(&thread2, NULL, &reader, NULL);
    pthread_create(&thread3, NULL, &writer, NULL);
    pthread_join(thread1, NULL);
    pthread_join(thread2, NULL);
    pthread_join(thread3, NULL);
    printf("Print in main function: num = %d\n", num);
    return 0;
}
条件变量

条件变量允许线程睡眠,直到满足某种条件,当满足条件时,可以向该线程发送信号通知唤醒

对于生产者消费者问题来说

缓冲区小于等于0的时候不允许消费者消费,消费者必须等待

缓冲区满时,不允许生产者网缓冲区生产,生产者必须等待

所以当生产者生产一个产品时,唤醒可能等待的消费者;当消费者消费一个产品时,唤醒可能等待的生产者

操作系统提供了条件变量API:pthread_cond_t pthread_cond_wait pthread_cond_signal

#include 
#include 
#include 
#include 
#include 
#include 
#include 

int MAX_BUF = 100;
int num = 0;

// 定义一个条件变量
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
// 定义一个互斥锁
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;

void* producer(void*){
    while(true){
        pthread_mutex_lock(&mutex);
        while (num >= MAX_BUF){
            // 等待
            printf("缓冲区满了, 等待消费者消费...\n");
            pthread_cond_wait(&cond, &mutex);
        }
        num += 1;
        printf("生产一个产品,当前产品数量为:%d\n", num);
        sleep(1);
        pthread_cond_signal(&cond);
        printf("通知消费者...\n");
        pthread_mutex_unlock(&mutex);
        sleep(1);
    }

}

void* consumer(void*){
    while(true){
        pthread_mutex_lock(&mutex);
        while (num <= 0){
            // 等待
            printf("缓冲区空了, 等待生产者生产...\n");
            pthread_cond_wait(&cond, &mutex);
        }
        num -= 1;
        printf("消费一个产品,当前产品数量为:%d\n", num);
        sleep(1);
        pthread_cond_signal(&cond);
        printf("通知生产者...\n");
        pthread_mutex_unlock(&mutex);
    }
}

int main(){
    pthread_t thread1, thread2;
    pthread_create(&thread1, NULL, &consumer, NULL);
    pthread_create(&thread2, NULL, &producer, NULL);
    pthread_join(thread1, NULL);
    pthread_join(thread2, NULL);
    return 0;
}

你可能感兴趣的:(线程同步)