linux中与线程同步的API

1 互斥锁

  pthread_mutex_init函数

  int pthread_mutex_init(pthread_mutex_t *restrict mutex, const pthread_mutexattr_t *restrict attr);
  这里的restrict关键字,表示指针指向的内容只能通过这个指针进行修改.
  restrict关键字:用来限定指针变量。被该关键字限定的指针变量所指向的内存操作,必须由本指针完成。初始化互斥量:

  • 示例
    pthread_mutex_t mutex;
  1. pthread_mutex_init(&mutex, NULL); 动态初始化。
  2. pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; 静态初始化

相关函数

  • pthread_mutex_destory函数
  • pthread_mutex_lock 函数
  • pthread_mutex_trylock函数
  • pthread_mutex_unlock 函数**
    以上5个函数的返回值都是:成功返回0,失败返回错误号

1.1 使用锁顺序

  pthread_mutex_t 类型

  1. pthread_mutex_t lock; 创建锁

  2. pthread_mutex_init; 初始化 1

  3. pthread_mutex_lock;加锁 1-- --> 0

  4. 访问共享数据(stdout)

  5. pthrad_mutext_unlock();解锁 0++ --> 1

  6. pthead_mutex_destroy;销毁锁

  • 示例代码

  • 访问表标准输出的时候,加上了锁。

#include <stdio.h>  
#include <string.h>  
#include <pthread.h>  
#include <stdlib.h>  
#include <unistd.h>  
 
 
void *tfn(void *arg)  
{  
	srand(time(NULL));  

	while (1) {  
	
	printf("hello ");  
	sleep(rand() % 3);  /*模拟长时间操作共享资源,导致cpu易主,产生与时间有关的错误*/  
	printf("world\n");  
	sleep(rand() % 3);  
}  
	  
	return NULL;  
}  
  
int main(void)  
{  
	pthread_t tid;  
	srand(time(NULL));  
  
	pthread_create(&tid, NULL, tfn, NULL);  
	while (1) {  
	  
		printf("HELLO ");  
		sleep(rand() % 3);  
		printf("WORLD\n");  
		sleep(rand() % 3);  
}  
	pthread_join(tid, NULL);  

	return 0;  
}  

  • 访问表标准输出的时候,加上了锁。
#include <stdio.h>  
#include <string.h>  
#include <pthread.h>  
#include <stdlib.h>  
#include <unistd.h>  
  
pthread_mutex_t mutex;      // 定义一把互斥锁  

void *tfn(void *arg)  
{  
	srand(time(NULL));  
  
	while (1) {  
		pthread_mutex_lock(&mutex);     // 加锁  
        printf("hello ");  
        sleep(rand() % 3);  // 模拟长时间操作共享资源,导致cpu易主,产生与时间有关的错误  
		printf("world\n");  
	        pthread_mutex_unlock(&mutex);   // 解锁  
	        sleep(rand() % 3);  
    }  
	  
	    return NULL;  
	}  
	  
int main(void)  
	{  
	    pthread_t tid;  
	    srand(time(NULL));  
	    int ret = pthread_mutex_init(&mutex, NULL);    // 初始化互斥锁  
        if(ret != 0){  
	        fprintf(stderr, "mutex init error:%s\n", strerror(ret));  
	        exit(1);  
	    }  
	  
	    pthread_create(&tid, NULL, tfn, NULL);  
	    while (1) {  
	        pthread_mutex_lock(&mutex);     // 加锁  
	        printf("HELLO ");  
	        sleep(rand() % 3);  
	        printf("WORLD\n");  
	        pthread_mutex_unlock(&mutex);   // 解锁  
	        sleep(rand() % 3);  
	    }  
	    pthread_join(tid, NULL);  
	      
	    pthread_mutex_destroy(&mutex);     // 销毁互斥锁  
	  
	    return 0;  
	}  

  • 注意事项:

      尽量保证锁的粒度, 越小越好。(访问共享数据前,加锁。访问结束【立即】解锁。)

      互斥锁,本质是结构体。 我们可以看成整数。 初值为 1。(pthread_mutex_init() 函数调用成功。)

      加锁: --操作, 阻塞线程。

      解锁: ++操作, 唤醒阻塞在锁上的线程。

      try锁:尝试加锁,成功–。失败,返回。同时设置错误号 EBUSY

2 读写锁

  pthread_rwlock_t rwlock;

  pthread_rwlock_init(&rwlock, NULL);

  pthread_rwlock_rdlock(&rwlock); try

  pthread_rwlock_wrlock(&rwlock); try

  pthread_rwlock_unlock(&rwlock);

  pthread_rwlock_destroy(&rwlock);

   以上函数都是成功返回0,失败返回错误号。

  pthread_rwlock_t 类型 用于定义一个读写锁变量

  pthread_rwlock_t rwlock

3 条件变量

  类型:pthread_cond_t 类型:用于条件变量。

  • pthread_cond_init 函数
  • pthread_cond_destroy 函数
  • pthread_cond_wait 函数
  • pthread_cond_timewait 函数
  • pthread_cond_signal 函数
  • pthread_cond_ broadcast 函数
  • pthread_cond_t 函数
  • pthread_cond_t 函数

以上6个函数的返回值都是
成功 0;
错误:失败直接返回错误号。

  • pthread_cond_init 函数
  1. pthread_cond_init(&cond, NULL); 动态初始化。

  2. pthread_cond_t cond = PTHREAD_COND_INITIALIZER; 静态初始化。

  • pthread_cond_wait 函

作用:
1) 阻塞等待条件变量满足
2) 解锁已经加锁成功的信号量 (相当于pthread_mutex_unlock(&mutex)),12两步为一个原子操作
3) 当条件满足,函数返回时,解除阻塞并重新申请获取互斥锁。重新加锁信号量 (相当于, pthread_mutex_lock(&mutex);)
在这里插入图片描述

  • 消费者-生产者模型
/*借助条件变量模拟 生产者-消费者 问题*/  
/* 互斥锁+条件变量*/
#include <stdlib.h>  
#include <unistd.h>  
#include <pthread.h>  
#include <stdio.h>  

/*链表作为公享数据,需被互斥量保护*/  
struct msg {  
	struct msg *next;  
	int num;  
};  
	  
struct msg *head;  
  
/* 静态初始化 一个条件变量 和 一个互斥量*/  
pthread_cond_t has_product = PTHREAD_COND_INITIALIZER;  
pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;  
  
void *consumer(void *p)  
{  
    struct msg *mp;  
  
    for (;;) {  
        pthread_mutex_lock(&lock);  
        while (head == NULL) {           //头指针为空,说明没有节点    可以为if吗  
            pthread_cond_wait(&has_product, &lock);   // 解锁,并阻塞等待  
        }  
        mp = head;        
        head = mp->next;                 //模拟消费掉一个产品  
        pthread_mutex_unlock(&lock);  
  
        printf("-Consume %lu---%d\n", pthread_self(), mp->num);  
        free(mp);  
        sleep(rand() % 5);  
    }  
}  
	  
void *producer(void *p)  
{  
    struct msg *mp;  
 
    for (;;) {  
        mp = malloc(sizeof(struct msg));  
        mp->num = rand() % 1000 + 1;        //模拟生产一个产品  
        printf("-Produce ---------------------%d\n", mp->num);  
		pthread_mutex_lock(&lock);  
        mp->next = head;  
	    head = mp;  
        pthread_mutex_unlock(&lock);  

        pthread_cond_signal(&has_product);  //将等待在该条件变量上的一个线程唤醒  
        sleep(rand() % 5);  
    }  
}  
  
int main(int argc, char *argv[])  
{  
    pthread_t pid, cid;  
    srand(time(NULL));  
  
    pthread_create(&pid, NULL, producer, NULL);  
    pthread_create(&cid, NULL, consumer, NULL);  
  
    pthread_join(pid, NULL);  
    pthread_join(cid, NULL);  
  
    return 0;  
}  
  • 消费者-生产者模型
#include <stdio.h>  
#include <stdlib.h>  
#include <string.h>  
#include <unistd.h>  
#include <errno.h>  
#include <pthread.h>  
	  
void err_thread(int ret, char *str)  
{  
    if (ret != 0) {  
        fprintf(stderr, "%s:%s\n", str, strerror(ret));  
        pthread_exit(NULL);  
    }  
}  
  
struct msg {  
    int num;  
    struct msg *next;  
};  
	  
struct msg *head;  
  
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;      // 定义/初始化一个互斥量  
pthread_cond_t has_data = PTHREAD_COND_INITIALIZER;      // 定义/初始化一个条件变量  
  
void *produser(void *arg)  
{  
    while (1) {  
        struct msg *mp = malloc(sizeof(struct msg));   
		
    mp->num = rand() % 1000 + 1;                        // 模拟生产一个数据`  
    printf("--produce %d\n", mp->num);  
  
    pthread_mutex_lock(&mutex);                         // 加锁 互斥量  
	mp->next = head;                                    // 写公共区域  
    head = mp;  
    pthread_mutex_unlock(&mutex);                       // 解锁 互斥量  

    pthread_cond_signal(&has_data);                     // 唤醒阻塞在条件变量 has_data上的线程.  

    sleep(rand() % 3);  
    }  
  
    return NULL;  
}  
void *consumer(void *arg)  
{  
    while (1) {  
        struct msg *mp;  
  
    pthread_mutex_lock(&mutex);                         // 加锁 互斥量  
    if (head == NULL) {  
        pthread_cond_wait(&has_data, &mutex);           // 阻塞等待条件变量, 解锁  
    }                                                   // pthread_cond_wait 返回时, 重写加锁 mutex  

    mp = head;  
    head = mp->next;  
  
    pthread_mutex_unlock(&mutex);                       // 解锁 互斥量  
    printf("---------consumer:%d\n", mp->num);  
  
    free(mp);  
    sleep(rand()%3);  
    }  
	  
    return NULL;  
}  

int main(int argc, char *argv[])  
{  
    int ret;  
    pthread_t pid, cid;  
	  
    srand(time(NULL));  
  
    ret = pthread_create(&pid, NULL, produser, NULL);           // 生产者  
    if (ret != 0)   
        err_thread(ret, "pthread_create produser error");  
  
    ret = pthread_create(&cid, NULL, consumer, NULL);           // 消费者  
    if (ret != 0)   
        err_thread(ret, "pthread_create consuer error");  
  
    pthread_join(pid, NULL);  
    pthread_join(cid, NULL);  
  
    return 0;  
}

  • 多个消费者代码
#include <stdio.h>  
#include <stdlib.h>  
#include <string.h>  
#include <unistd.h>  
#include <errno.h>  
#include <pthread.h>  
  
void err_thread(int ret, char *str)  
{  
    if (ret != 0) {  
    fprintf(stderr, "%s:%s\n", str, strerror(ret));  
        pthread_exit(NULL);  
    }  
}  
	  
struct msg {  
    int num;  
    struct msg *next;  
};  
  
struct msg *head;  
  
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;      // 定义/初始化一个互斥量  
pthread_cond_t has_data = PTHREAD_COND_INITIALIZER;      // 定义/初始化一个条件变量  
  
void *produser(void *arg)  
{  
    while (1) {  
    struct msg *mp = malloc(sizeof(struct msg));  
  
    mp->num = rand() % 1000 + 1;                        // 模拟生产一个数据`  
    printf("--produce %d\n", mp->num);  
  
    pthread_mutex_lock(&mutex);                         // 加锁 互斥量  
    mp->next = head;                                    // 写公共区域  
    head = mp;  
    pthread_mutex_unlock(&mutex);                       // 解锁 互斥量  
  
   pthread_cond_signal(&has_data);                     // 唤醒阻塞在条件变量 has_data上的线程.  
         
    sleep(rand() % 3);  
}  
 
	return NULL;  
} 
	
void *consumer(void *arg)  
{  
    while (1) {  
    struct msg *mp;  
  
    pthread_mutex_lock(&mutex);                         // 加锁 互斥量  
        if (head == NULL) {  
        pthread_cond_wait(&has_data, &mutex);           // 阻塞等待条件变量, 解锁  
    }                                                   // pthread_cond_wait 返回时, 重写加锁 mutex  
 
    mp = head;  
    head = mp->next;  
  
    pthread_mutex_unlock(&mutex);                       // 解锁 互斥量  
    printf("---------consumer:%d\n", mp->num);  
  
    free(mp);  
    sleep(rand()%3);  
}  
  
    return NULL;  
}  
  
int main(int argc, char *argv[])  
{  
    int ret;  
    pthread_t pid, cid;  
  
    srand(time(NULL));  
  
    ret = pthread_create(&pid, NULL, produser, NULL);           // 生产者  
    if (ret != 0)   
    err_thread(ret, "pthread_create produser error");  
  
    ret = pthread_create(&cid, NULL, consumer, NULL);           // 消费者  
    if (ret != 0)   
		err_thread(ret, "pthread_create consuer error");  

    pthread_join(pid, NULL);  
    pthread_join(cid, NULL);  
  
    return 0;  
}  

4 信号量

信号量:

  1. 应用于线程、进程间同步。
  2. 互斥量,虽然访问是有序的,但是程序的并行性降低了。
  3. 信号与信号量没有关系。只是翻译的比较接近而已。
  4. 相当于 初始化值为 N 的互斥量。 N值,表示可以同时访问共享数据区的线程数。

API:

  • sem_t sem; 定义类型。
  • int sem_init(sem_t *sem, int pshared, unsigned int value);

  sem_init(&sem,0 ,N);
  参数:
  sem: 信号量

  pshared: 0: 用于线程间同步

       1: 用于进程间同步

value:N值。(指定同时访问的线程数)
   返回值
    成功:0
    错误:-1

  • sem_destroy();

  • sem_wait(); 一次调用,做一次-- 操作, 当信号量的值为 0 时
    再次 – 就会阻塞。 (类比 pthread_mutex_lock)

  • sem_post(); 一次调用,做一次++ 操作. 当信号量的值为 N 时,
    再次 ++ 就会阻塞。(类比 pthread_mutex_unlock)

  信号量的初值决定了同时访问的线程数

  • 信号量实现生产者消费者模型
/*信号量实现 生产者 消费者问题*/  
	  
#include <stdlib.h>  
#include <unistd.h>  
#include <pthread.h>  
#include <stdio.h>  
#include <semaphore.h>  
  
#define NUM 5                 
  
int queue[NUM];                                     //全局数组实现环形队列  
sem_t blank_number, product_number;                 //空格子信号量, 产品信号量  
  
void *producer(void *arg)  
{  
    int i = 0;  
  
    while (1) {  
        sem_wait(&blank_number);                    //生产者将空格子数--,为0则阻塞等待  
        queue[i] = rand() % 1000 + 1;               //生产一个产品  
        printf("----Produce---%d\n", queue[i]);          
        sem_post(&product_number);                  //将产品数++  
  
        i = (i+1) % NUM;                            //借助下标实现环形  
		sleep(rand()%1);  
	}  
}  
	  
void *consumer(void *arg)  
{  
    int i = 0;  
  
    while (1) {  
        sem_wait(&product_number);                  //消费者将产品数--,为0则阻塞等待  
        printf("-Consume---%d\n", queue[i]);  
        queue[i] = 0;                               //消费一个产品   
        sem_post(&blank_number);                    //消费掉以后,将空格子数++  
  
        i = (i+1) % NUM;  
        sleep(rand()%3);  
    }  
}  
  
int main(int argc, char *argv[])  
{  
    pthread_t pid, cid;  
  
    sem_init(&blank_number, 0, NUM);                //初始化空格子信号量为5, 线程间共享 -- 0  
    sem_init(&product_number, 0, 0);                //产品数为0  
  
    pthread_create(&pid, NULL, producer, NULL);  
    pthread_create(&cid, NULL, consumer, NULL);  
  
    pthread_join(pid, NULL);  
    pthread_join(cid, NULL);  
  
    sem_destroy(&blank_number);  
    sem_destroy(&product_number);  
  
	return 0;  
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值