20.线程同步

2020-05-04  本文已影响0人  陈忠俊

1.mutex互斥锁

常用的互斥锁函数

pthread_mutex_init(3) #初始化锁,返回0
pthread_mutex_destroy(3) #指定要销毁锁的地址,成功返回0
pthread_mutex_lock(3) # 如果锁被其他线程占用,阻塞等待,直到占用该锁的线程释放锁。否则,立即上锁并返回
pthread_mutext_trylock(3) #尝试加锁,如不能,返回错误。可以,立即加锁并返回
pthread_mutext_unlock(3) #释放锁

代码实现,两个线程交替计算

#include<stdio.h>
#include<pthread.h>
#include<unistd.h>
#include<sys/types.h>


pthread_mutex_t mutex;
int value = 0;

void *temp(void *arg){
    int tmp;
    for(int i = 0; i < 5000; i++){
        //lock now
        pthread_mutex_lock(&mutex);
        tmp = value;
        tmp++;
        printf("threadId: %lu\ttmp = %d\n", pthread_self(), tmp);
        value = tmp;
        pthread_mutex_unlock(&mutex);
    }
    return NULL;
}

int main(void){
    pthread_mutex_init(&mutex, NULL);
    pthread_t thread_1, thread_2;
    pthread_create(&thread_1, NULL, temp, NULL);
    pthread_create(&thread_2, NULL, temp, NULL);
    pthread_join(thread_1, NULL);
    pthread_join(thread_2, NULL);

    pthread_mutex_destroy(&mutex);

    return 0;
}

2.条件变量

常用函数

pthread_cond_init(3) #初始化一个条件变量
pthread_cond_destroy(3) # 销毁条件变量的地址
pthread_cond_signal(3) # 如果有多个线程等待条件变量为真,从其中选出一个执行。如果没有线程等待条件变量为真,什么都不做。
pthread_cond_broadcast(3) #通知多个有等待条件变量为真的线程执行。如果没有条件变量为真,则什么都不做。
pthread_cond_wait(3) # 原子的解锁并等待条件变量为真。当条件变量为真的时候,重新获取mutex锁
pthread_cond_timewait(3) 

生产者消费者模型

#include <t_stdio.h>
#include <pthread.h>
#include <time.h>
#include <stdlib.h>
#include <unistd.h>
//定义链表节点的类型
typedef struct node{
    int data;
    struct node *next;
}node_t;

node_t *head=NULL;
pthread_mutex_t mutex;//定义锁类型的变量
pthread_cond_t cond;//定义条件变量
//生产者线程
void *product(void *arg){
    node_t *new;
    while(1){
        //生产一个新节点
        new=(node_t *)malloc(sizeof(node_t));
        new->data=rand()%1000+1;
        new->next=NULL;
        printf("p:%d\n",new->data);
        //加锁
        pthread_mutex_lock(&mutex);
        
        new->next=head;
        head=new;
        //解锁
        pthread_mutex_unlock(&mutex);
       
        pthread_cond_signal(&cond);
        sleep(rand()%3+1);    
    }
    return NULL;
}
//消费者线程
void *consume(void *arg){
    node_t *tmp;
    while(1){
        //加锁
        pthread_mutex_lock(&mutex);
        while(head==NULL)
            pthread_cond_wait(&cond,&mutex);
            //重新获取mutex锁
        tmp=head;
        head=head->next;
        //解锁
        pthread_mutex_unlock(&mutex);
        printf("c:%d\n",tmp->data);
        //消费该节点
        free(tmp);
        tmp=NULL;
        sleep(rand()%3+1);    
    }
    return NULL;
}

int main(void){
    srand(time(NULL));
    //初始化mutex变量
    pthread_mutex_init(&mutex,NULL);
    pthread_cond_init(&cond,NULL);
    //创建两个线程 生产者  消费者
    pthread_t pid,cid;
    pthread_create(&pid,NULL,product,NULL);
    pthread_create(&cid,NULL,consume,NULL);
    //等待线程的汇合
    pthread_join(pid,NULL);
    pthread_join(cid,NULL);
    //销毁mutex变量
    pthread_mutex_destroy(&mutex);
    pthread_cond_destroy(&cond);
    
    return 0;
}

3.信号量

常用的函数

sem_init # 初始化一个匿名的信号量
sem_destroy # 销毁信号量
sem_post # 解锁信号量,信号量+1,如果有线程或者进程调用阻塞在该信号量,则被唤醒,继续锁定信号量(-1)
sem_wait # 信号量值减1操作。如果当前信号量的值为0,阻塞等待直到其他进程或线程使该信号量大于0为止
sem_trywait # 尝试一次操作,如果信号量的值为0,立即返回,返回错误
sem_timedwait # 指定等待的时间,超时返回超时错误

信号量控制的生产者和消费者模型

#include <pthread.h>
#include <t_stdio.h>
#include <unistd.h>
#include <time.h>
#include <stdlib.h>
#include <semaphore.h>
typedef int que_t[7];
sem_t p,c; 
que_t que;//定义队列

//生产者线程
void *product(void *arg){
    int index=0;
    while(1){
        sem_wait(&p);//如果p的值=0,阻塞
        que[index]=rand()%500+1;
        printf("p:%d\n",que[index]);
        index=(index+1)%7;
        sem_post(&c);//可消费的数量加1
        sleep(rand()%3+1);
    }
}
//消费者线程
void *consume(void *arg){
    int index=0;
    int tmp;
    while(1){
        sem_wait(&c);
        tmp=que[index];
        que[index]=-1;
        printf("c:%d\n",tmp);
        index=(index+1)%7;
        sem_post(&p);//可生产数量加1
        sleep(rand()%3+1);
    }
}
int main(void){
    srand(time(NULL));
    //初始化信号量
    sem_init(&p,0,7);
    sem_init(&c,0,0);
    //创建两个线程,分别用于生产者和消费者
    pthread_t pid,cid;
    pthread_create(&pid,NULL,product,NULL);
    pthread_create(&cid,NULL,consume,NULL);
    //阻塞等待线程汇合
    pthread_join(pid,NULL);
    pthread_join(cid,NULL);
    //销毁信号量
    sem_destroy(&p);
    sem_destroy(&c);
    return 0;
}

上一篇下一篇

猜你喜欢

热点阅读