线程的控制之-线程同步(含读者与写者问题)及(生产者和消费者问题)

线程同步:

1,进程同步的方法
2,互斥量,读写锁,条件变量的区别
3,合理同步,避免死锁

<1>互斥量
1)为什么要使用互斥变量?

例子1:不加互斥量条件下,同一个共享变量(资源)在不同线程间苯调用,其值无法保证。导致结果不一;如下例全局共享变量变量i被线程1和线程2交叉调用会导致不同的输出结果;

#include"stdio.h"
#include"unistd.h"
#include"sys/types.h"
#include"pthread.h"
#include"stdlib.h"
#include"string.h"
typedef struct Mutex{
        int mux_1;
        int mux_2;
  }Mutex;
  int i;//全局共享变量
  Mutex Mt;//互斥变量
  void *pthread_fun1(void *arg)
  {
    while(1)
    {
        Mt.mux_1=i;
        Mt.mux_2=i;
        if(Mt.mux_1 !=Mt.mux_2)
        {
        printf("%s Mt.mux_1=%d   Mt.mux_2=%d\n",arg,Mt.mux_1,Mt.mux_2);
        break;
        }
        ++i;
    }
 return (void*)1;
 }
 
 void *pthread_fun2(void *arg)
  {
    while(1)
    {
        Mt.mux_1=i;
        Mt.mux_2=i;
        if(Mt.mux_1 !=Mt.mux_2)
        {
        printf(" %s Mt.mux_1=%d   Mt.mux_2=%d\n",arg,Mt.mux_1,Mt.mux_2);
        break;
        }
        ++i;
    }
 return (void*)1;
 }
 
 int main()
 {
        pthread_t tid1,tid2;
        int err1,err2;
        int ini_mux;
        
        err1=pthread_create(&tid1,NULL,pthread_fun1,"thread1");
        if(err1 !=0)
        {
        printf("create new thread1\n");
        return -1;
        }
        err2=pthread_create(&tid2,NULL,pthread_fun2,"thread2");
        if(err2 !=0)
        {
        printf("create new thread2\n");
        return -2;
        }
        
        pthread_join(tid1,NULL);//等待新线程执行完
        pthread_join(tid2,NULL);//等待新线程执行完
        
        return 0;
 }

输出结果如图:

没有设置互斥量的i(共享资源)的值在任意不同线程的调用中会发生值的随机改变。
2)互斥锁的初始化和销毁。

3)加锁和解锁

4)互斥锁实例

例子2:基于例子1的情况下,为共享资源i建立互斥量,确保i在某个线程调用时不会被其他线程抢占调用。建立文件pthread_mutex_t.c;内容如下

#include"stdio.h"
#include"unistd.h"
#include"sys/types.h"
#include"pthread.h"
#include"stdlib.h"
#include"string.h"
typedef struct Mutex{
        int mux_1;
        int mux_2;
  }Mutex;
  int i;//全局共享变量
  Mutex Mt;//结构体对象
  pthread_mutex_t mutex;//互斥量
  void *pthread_fun1(void *arg)
  {
    while(1)
    {
        pthread_mutex_lock(mutex);//p操作锁住i资源,确保线程用完前不被抢占
        Mt.mux_1=i;
        Mt.mux_2=i;
        if(Mt.mux_1 != Mt.mux_2)
        {
        printf("%s Mt.mux_1=%d  Mt.mux_2=%d\n",arg,Mt.mux_1,Mt.mux_2);
        }
        ++i;
       pthread_mutex_unlock(mutex);//解锁释放i资源,确保其他线程可以用
    }
 return (void*)1;
 }
 
 void *pthread_fun2(void *arg)
  {
  pthread_mutex_lock(mutex);
    while(1)
    {
        pthread_mutex_lock(mutex);//p操作锁住i资源,确保线程用完前不被抢占
        Mt.mux_1=i;
        Mt.mux_2=i;
         if(Mt.mux_1 != Mt.mux_2)
        {
        printf(" %s Mt.mux_1=%d   Mt.mux_2=%d\n",arg,Mt.mux_1,Mt.mux_2);
        }
        ++i;
       pthread_mutex_unlock(mutex);//解锁释放i资源,确保其他线程可以用
    }
    }
 return (void*)1;
 }
 
 int main()
 {
        pthread_t tid1,tid2;
        int err1,err2;
        int ini_mux;
        //初始化互斥量,这样互斥量才可用
        ini_mux=pthread_mutex_init(metux);
        if(ini_mux !=0)
        {
        printf(" inital mutex failure\n");
        return ini_mux;
        }
        
        err1=pthread_create(&tid1,NULL,pthread_fun1,"thread1");
        if(err1 !=0)
        {
        printf("create new thread1\n");
        return -1;
        }
        err2=pthread_create(&tid2,NULL,pthread_fun2,"thread2");
        if(err2 !=0)
        {
        printf("create new thread2\n");
        return -2;
        }
        
        pthread_join(tid1,NULL);//等待新线程的执行结束
        pthread_join(tid2,NULL);//等待新线程的执行结束
        
        return 0;
        }
        
        

运行结果如下:

如图没有打印出数据,说在设置了互斥量metux后i资源就不会在某个线程调用时被其他线程抢占调用了,从而mux_1!=mux_2这个条件永远不成立。就不会打印结果。
5)死锁的解剖




<2>读写锁(读者与写者问题)
1)什么是读写锁,它与互斥锁的区别

2)读写锁的初始化和销毁:

3)枷锁和解锁:

4)读写锁实例:

例子3:验证一个共享资源可以被多个线程同时读加锁进行读取,即同时进行多个读加锁。

#include"stdio.h"
#include"unistd.h"
#include"sys/types.h"
#include"pthread.h"
#include"stdlib.h"
#include"string.h"
pthread_rwlock_t rwlock;//全局读写锁对象
  void *pthread_fun1(void *arg)
  {
   
      pthread_rwlock_rdlock(&rwlock);//加读模式锁
     printf("new thread 1\n");//打印
    sleep(5);//睡眠5秒让出cpu
    printf("here is thread 1 exit\n");
   pthread_rwlock_unlock(&rwlock);//解锁
 return (void*)1;
 }
 
 void *pthread_fun2(void *arg)
  {
      pthread_rwlock_rdlock(&rwlock);//加读模式锁
     printf(" new thread 2\n");
    sleep(5);//睡眠5秒让出cpu
    printf("here is thread 2 exit\n");
   pthread_rwlock_unlock(&rwlock);//解锁
 return (void*)1;
 }
 
 int main()
 {
        pthread_t tid1,tid2;
        int err1,err2;
        int er_lock;
        
        er_lock=pthread_rwlock_init(&rwlock,NULL);//初始化
        if(er_lock !=0)
        {
        printf("init rwlock failure\n");
        return er_lock;
        }
        
        err1=pthread_create(&tid1,NULL,pthread_fun1,"thread1");
        if(err1 !=0)
        {
        printf("create new thread1\n");
        return -1;
        }
        err2=pthread_create(&tid2,NULL,pthread_fun2,"thread2");
        if(err2 !=0)
        {
        printf("create new thread2\n");
        return -2;
        }
        
        pthread_join(tid1,NULL);//等待新线程执行完
        pthread_join(tid2,NULL);//等待新线程执行完
        
        return 0;
 }

运行结果如图:

如图new thread 2和new thread 1被同时打印出,证实了一个共享资源变量可以被多个线程同时进行读加锁模式。
例子4:基于例子3将新线程里的读加锁pthread_rwlock_rdlock改为写加锁pthread_rwlock_rdlock,在进行编译运行,结果如下:

如图线程2先读加锁然后写完解锁后,线程1才能进程写加锁然后开始写。
写加锁和读加锁是互斥的,写时不能读,读时不能写。
<3>条件变量(生成者和消费者问题)
1)条件变量的引入

2)条件变量的初始化和销毁

3)条件变量的使用

4)条件变量实例(生产者和消费者)

建立文件phtread_producer_consmer.c;内容如下

#include"stdio.h"
#include"unistd.h"
#include"sys/types.h"
#include"pthread.h"
#include"stdlib.h"
#include"string.h"

#define BUFFER_SIZE   5  //产品库存大小
#define PRODUCT_CNT  30 //产品生产总数

typedef struct product_cons {
    int buffer[BUFFER_SIZE];//生产产品
    pthread_mutex_t lock;//互斥锁 volatile int
    int readpos,writepos;//读写的位置
    pthread_cond_t notempty;//条件变量,非空
    pthread_cond_t notfull;//条件变量,非满
    }Buffer;
    Buffer buffer;//全局对象
    void init(Buffer *p)
    {
        pthread_mutex_init(&p->lock,NULL);//初始化互斥锁
        pthread_cond_init(&p->notempty,NULL);//初始化条件变量
        pthread_cond_init(&p->notfull,NULL);//初始化条件变量
        p->readpos =0;//初始化读位置
        p->writepos =0;//初始化写位置
    }
    void finish(Buffer *p)
    {
        pthread_mutex_destroy(&p->lock);//销毁互斥锁
        pthread_cond_destroy(&p->notempty);//销毁条件变量
        pthread_cond_destroy(&p->notfull);//销毁条件变量
        p->readpos =0;//读位置归零
        p->writepos =0;//写位置归零
    }
    //存储一个数据到buffer
    void put(Buffer *p,int data)//生产产品函数(入队)
    {
        
        pthread_mutex_lock(&p->lock);//写前加写模式锁
        if((p->writepos+1)%BUFFER_SIZE==p->readpos)
        {
        printf("producer wait for not full\n");
        pthread_cond_wait(&p->notfull,&p->lock);
        }
        p->writepos=(p->writepos+1)%BUFFER_SIZE;
        p->buffer[p->writepos]=data;
        
        pthread_cond_signal(&p->notempty);
        pthread_mutex_unlock(&p->lock);
        
    }
    
    //读,从buffer中 移除一个数据
    int get(Buffer *p)//消费产品函数(出队)
    {
       int data;
        pthread_mutex_lock(&p->lock);//读取前加读模式锁
        
        if(p->readpos == p->writepos)//队空
        {
        printf("consumer wait for not empty\n");
        pthread_cond_wait(&p->notempty,&p->lock);
    }
    p->readpos=(p->readpos+1)%BUFFER_SIZE;
    data = p->buffer[p->readpos];
    
    pthread_cond_signal(&p->notfull);
    pthread_mutex_unlock(&p->lock);
    
    return  data;;
  }
    void *producer(void *data)//子线程,生产者
    {
        int n;
        for(n=1;n<=50;++n)//生产50个产品
        {
            sleep(1);
            printf("producer put the %d product ... \n",n);
            put(&buffer,n);
            printf("producer put the %d product success\n",n);
        }
        
        printf("producer stopped");
        
        return NULL;
    }
    
    void *consumer(void *data)
    {
        static int cnt =0;
        int num;
        while(1)
        {
            sleep(2);
            printf("consumer get product ...\n");
            num = get(&buffer);
            printf("consumer get the %d product success\n",num);
            if(++cnt == PRODUCT_CNT)
                break;
        }
        printf("consumer stopped\n");
        return NULL;
      }
    int main(int argc,char *argv[])
    {
        pthread_t th_a,th_b;
        void *rval;
        
        init(&buffer);
        
        pthread_create(&th_a,NULL,producer,0);
        pthread_create(&th_b,NULL,consumer,0);
        
        pthread_join(th_a,&rval);
        pthread_join(th_b,&rval);
        
        finish(&buffer);
        
        return 0;
    }

        

运行结果如下:

发布了50 篇原创文章 · 获赞 13 · 访问量 1830

猜你喜欢

转载自blog.csdn.net/weixin_38251305/article/details/103988340