ICode9

精准搜索请尝试: 精确搜索
首页 > 编程语言> 文章详细

2019年8月15日星期四(系统编程)

2019-08-15 18:01:01  阅读:241  来源: 互联网

标签:rwlock 15 int cond 2019 pthread mutex NULL 星期四


2019年8月15日星期四

一. 线程互斥方式 - 互斥锁。

1. 什么是互斥锁?特点如何?

互斥锁是专门用于处理线程互斥的一个方式,它有两种状态:上锁状态/解锁状态。

特点:如果处理上锁状态,则不能再上锁,直到解锁为止才能再上锁。如果是处于解锁状态,则不能再解锁了,直到上锁了才能再解锁。

2. 关于线程互斥锁API函数接口?

0)定义互斥锁的变量(pthread_mutex_t-> 互斥锁的数据类型)

   pthread_mutex_t mutex;

1)初始化互斥锁  -> pthread_mutex_init()  -> man 3 pthread_mutex_init

功能: initialize a mutex  -> 初始化互斥锁

使用格式:

       #include <pthread.h>

       -> 动态初始化

    int pthread_mutex_init(pthread_mutex_t *mutex,const pthread_mutexattr_t *attr);

      

       mutex:  互斥锁的地址

       attr:   互斥锁的属性,一般填NULL

       返回值:

              成功:0

              失败:错误码

       -> 静态初始化

   pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;

2)上锁  -> pthread_mutex_lock() -> man 3 pthread_mutex_lock

功能:lock a mutex

使用格式:

       #include <pthread.h>

       int pthread_mutex_lock(pthread_mutex_t *mutex);

       mutex:必须是已经初始化过的互斥锁的地址

       返回值:

              成功:0

              失败:错误码

3)解锁  -> pthread_mutex_unlock() -> man 3 pthread_mutex_unlock

功能:unlock a mutex

使用格式:

         #include <pthread.h>           

        int pthread_mutex_unlock(pthread_mutex_t *mutex);

           mutex:必须是已经初始化过的互斥锁的地址

       返回值:

              成功:0

              失败:错误码

4)销毁互斥锁  -> pthread_mutex_destroy()  -> man 3 pthread_mutex_destroy

功能:

使用格式:

       #include <pthread.h>

       int pthread_mutex_destroy(pthread_mutex_t *mutex);

       mutex:必须是已经初始化过的互斥锁的地址

       返回值:

              成功:0

              失败:错误码

  练习1:使用互斥锁完成作业2。

#include "head.h"

 

pthread_mutex_t m = PTHREAD_MUTEX_INITIALIZER;

 

//Jack发

void *routine1(void *arg)

{

       char *p = (char *)arg;

      

       while(1)

       {

              //在访问共享内存前必须先上锁

              pthread_mutex_lock(&m);

             

              fgets(p,1024,stdin); //访问共享内存

             

              //访问完共享内存后必须要解锁

              pthread_mutex_unlock(&m);

             

              if(strncmp(p,"quit",4) == 0)

              {

                     break;

              }

             

              usleep(100000);

       }

      

       pthread_exit(NULL);

}

 

//Rose收

void *routine2(void *arg)

{

       usleep(100000);

       char *p = (char *)arg;

      

       while(1)

       {

              //在访问共享内存前必须先上锁,由于睡觉了,后上锁

              pthread_mutex_lock(&m);

             

              printf("from Jack:%s",p);

             

              pthread_mutex_unlock(&m);

             

              if(strncmp(p,"quit",4) == 0)

              {

                     break;

              }

             

              usleep(200000);

       }

      

       pthread_exit(NULL);

}

 

int main(int argc,char *argv[])

{

       //1. 申请key与ID号

       key_t key = ftok(".",10);

       int shmid = shmget(key,1024,IPC_CREAT|0666);

      

       //2. 映射内存空间

       char *p = shmat(shmid,NULL,0);

      

       //3. 产生Jack线程与Rose线程

       pthread_t tid1,tid2;

       pthread_create(&tid1,NULL,routine1,(void *)p);

       pthread_create(&tid2,NULL,routine2,(void *)p);

      

       //4. 接合线程

       pthread_join(tid1,NULL);

       pthread_join(tid2,NULL);

      

       //5. 撤销映射,删除共享内存ID

       shmdt(p);

       shmctl(shmid,IPC_RMID,NULL);

      

       return 0;

}

 

结论:只要工程涉及到共享资源(共享内存,链表,文件..),就必须在访问前上锁,访问后解锁。

二. 读写锁。

1. 互斥锁有什么缺陷?

互斥锁无论是访问资源,还是修改资源都必须要上锁,而且在上锁期间不能被别的线程再上锁。

访问资源(一起读这本书) -> 同时上读锁  ->  读锁其实是一把共享锁。

修改资源(修改书本的数据)  -> 不能同时上写锁  -> 写锁其实是一把互斥锁。

即有读锁,又有写锁,那么我们就称之为读写锁。

2. 关于读写锁的API函数接口?

1)初始化读写锁  -> pthread_rwlock_init()  -> man 3 pthread_rwlock_init

功能:initialize a read-write lock object

使用格式:

        #include <pthread.h>

       int pthread_rwlock_init(pthread_rwlock_t *rwlock,const pthread_rwlockattr_t *attr);

       rwlock: 读写锁的地址

       attr: 属性,一般填NULL

       返回值:

              成功:0

              失败:错误码

2)读锁上锁  -> pthread_rwlock_rdlock()  -> man 3 pthread_rwlock_rdlock

功能:lock a read-write lock object for reading

使用格式:

       #include <pthread.h>

       int pthread_rwlock_rdlock(pthread_rwlock_t *rwlock);

       rwlock:读写锁的地址

       返回值:

              成功:0

              失败:错误码

3)写锁上锁  -> pthread_rwlock_wrlock()  -> man 3 pthread_rwlock_wrlock

功能:lock a read-write lock object for writing

使用格式:

       #include <pthread.h>

       int pthread_rwlock_wrlock(pthread_rwlock_t *rwlock);

       rwlock:读写锁的地址

       返回值:

              成功:0

              失败:错误码

4)读写锁解锁  -> pthread_rwlock_unlock()  -> man 3 pthread_rwlock_unlock

功能:unlock a read-write lock object

使用格式:

       #include <pthread.h>

       int pthread_rwlock_unlock(pthread_rwlock_t *rwlock);

       rwlock:读写锁的地址

       返回值:

              成功:0

              失败:错误码

5)销毁读写锁  -> pthread_rwlock_destroy()  -> man 3 pthread_rwlock_destroy

功能:destroy a read-write lock object

使用格式:

       #include <pthread.h>

       int pthread_rwlock_destroy(pthread_rwlock_t *rwlock);

       rwlock:读写锁的地址

       返回值:

              成功:0

              失败:错误码

  练习2:临界资源"int a",两个线程想打印a的值,两个线程想修改a的值。

         验证:

              1)读锁可以同时上,但是写锁不可以同时上。

              2)读锁写锁能不能同时上?  -> 不可以,写锁等到读锁解开之后才能上写锁。

#include "head.h"

 

int a = 100;//临界资源

pthread_rwlock_t rwlock; //读写锁变量

 

//线程1任务:打印a的值,花了3秒

void *fun1(void *arg)

{

       //访问临界资源前,需要上读锁

       pthread_rwlock_rdlock(&rwlock);

       printf("fun1 rdlock lock!\n");

       printf("fun1 a = %d\n",a);

       sleep(3);

      

       //访问完临界资源,需要解锁

       pthread_rwlock_unlock(&rwlock);

       printf("fun1 rdlock unlock!\n");

       pthread_exit(NULL);

}

 

//线程2任务:打印a的值,花了5秒

void *fun2(void *arg)

{

       //访问临界资源前,需要上读锁

       pthread_rwlock_rdlock(&rwlock);

       printf("fun2 rdlock lock!\n");

       printf("fun2 a = %d\n",a);

       sleep(5);

      

       //访问完临界资源,需要解锁

       pthread_rwlock_unlock(&rwlock);

       printf("fun2 rdlock unlock!\n");

       pthread_exit(NULL);

}

 

 

//线程3任务:修改a的值,花了4S  a = 50

void *fun3(void *arg)

{

       pthread_rwlock_wrlock(&rwlock);

       printf("fun3 wrlock lock!\n");

      

       a = 50;

       sleep(4);

       pthread_rwlock_unlock(&rwlock);

       printf("fun3 wrlock unlock!\n");

       pthread_exit(NULL);

}

 

//线程4任务:修改a的值,花了6S  a = 30

void *fun4(void *arg)

{

       pthread_rwlock_wrlock(&rwlock);

       printf("fun4 wrlock lock!\n");

       a = 30;

       sleep(6);

       pthread_rwlock_unlock(&rwlock);

       printf("fun4 wrlock unlock!\n");

       pthread_exit(NULL);

}

 

void *routine(void *arg)

{

       int i;

       for(i=0;i<1000000;i++)

       {

              printf("%d\n",i);

              sleep(1);

       }

}

 

int main(int argc,char *argv[])

{

       //0. 计算时间的流逝

       pthread_t tid;

       pthread_create(&tid,NULL,routine,NULL);

      

       //1. 初始化读写锁

       pthread_rwlock_init(&rwlock,NULL);

      

       //2. 产生子线程

       pthread_t tid1,tid2,tid3,tid4;

       pthread_create(&tid1,NULL,fun1,NULL);

       pthread_create(&tid2,NULL,fun2,NULL);

      

       pthread_create(&tid3,NULL,fun3,NULL);

       pthread_create(&tid4,NULL,fun4,NULL);

      

       //3. 接合线程

       pthread_join(tid1,NULL);

       pthread_join(tid2,NULL);

       pthread_join(tid3,NULL);

       pthread_join(tid4,NULL);

      

       //4. 销毁读写锁

       pthread_rwlock_destroy(&rwlock);

      

       return 0;

}

三. 条件变量。

1. 什么是条件变量?特点?

线程因为某个条件不成立/情况不允许情况下,进入一个变量中等待,这个可以存放这些线程的变量就叫做条件变量。

条件变量一定是与互斥锁一起使用。

2. 关于条件变量的函数接口?

0)定义条件变量 (数据类型:pthread_cond_t)

   pthread_cond_t v;

1)初始化条件变量?  -> pthread_cond_init() -> man 3 pthread_cond_init

功能:initialize condition variables

使用格式:

       动态初始化:

        #include <pthread.h>

       int pthread_cond_init(pthread_cond_t *cond,const pthread_condattr_t *attr);

       cond: 条件变量的地址

       attr: 条件变量的属性,一般填NULL。

       返回值:

              成功:0

              失败:错误码

       静态初始化:

       pthread_cond_t cond = PTHREAD_COND_INITIALIZER;

2)如何进入条件变量中等待?  -> pthread_cond_wait() -> man 3 pthread_cond_wait

   如果满足进入条件变量的条件,则会进去等待,并且会自动解锁。

功能:wait on a condition

使用格式:

       #include <pthread.h>

     int pthread_cond_wait(pthread_cond_t *cond,pthread_mutex_t *mutex);

       cond:条件变量的地址

       mutex:互斥锁的地址

       返回值:

              成功:0

              失败:错误码

3)如何唤醒条件变量中等待的线程? 

广播: 唤醒所有在条件变量中等待的线程。  -> pthread_cond_broadcast() -> man 3 pthread_cond_broadcast

单播: 随机唤醒条件变量中任意一个线程。  -> pthread_cond_signal()    -> man 3 pthread_cond_signal

功能:broadcast or signal a condition     

使用格式:

       #include <pthread.h>

       int pthread_cond_broadcast(pthread_cond_t *cond);

       int pthread_cond_signal(pthread_cond_t *cond);

       cond:条件变量的地址     

       返回值:

              成功:0

              失败:错误码

注意: 从条件变量中出来的线程,会自动上锁。

4)销毁条件变量  -> pthread_cond_destroy()  -> man 3 pthread_cond_destroy

功能:destroy condition variables

使用格式:

       #include <pthread.h>

       int pthread_cond_destroy(pthread_cond_t *cond);

       cond:条件变量的地址

       返回值:

              成功:0

              失败:错误码

#include "head.h"

pthread_mutex_t m = PTHREAD_MUTEX_INITIALIZER;//初始化互斥锁

pthread_cond_t v = PTHREAD_COND_INITIALIZER;//初始化条件变量

int sum = 400;

 

//任务: 就是去银行卡扣200块

void *routine(void *arg)

{

       //1. 访问临界资源(银行卡)前,都需要上锁

       pthread_mutex_lock(&m);

      

       //2. 询问条件是否满足?

       while(sum < 200) //当拿不到钱时

       {

              //就进入条件变量中等待

              pthread_cond_wait(&v,&m); //自动解锁。

       }

      

       /* 从循环出来,一定是被唤醒并且余额>=200 */

       printf("before money:%d\n",sum);

       //拿钱

       sum -= 200;

       printf("after money:%d\n",sum);

      

       //拿到钱后,要主动解锁。

       pthread_mutex_unlock(&m);

      

       //走人

       pthread_exit(NULL);

}

 

void *routine1(void *arg)

{

       int i;

       for(i=0;i<1000000;i++)

       {

              printf("%d\n",i);

              sleep(1);

       }

}

 

int main(int argc,char *argv[])

{

       //0. 计算时间的流逝

       pthread_t tid_test;

       pthread_create(&tid_test,NULL,routine1,NULL);

      

       int i;

       pthread_t tid[5];

       //1. 产生5个子线程

       for(i=0;i<5;i++)

       {

              pthread_create(&tid[i],NULL,routine,NULL);

       }

      

       sleep(5);  //2个能拿到钱,3个在条件变量中睡觉。

       /* 主线程在访问临界资源前,也必须上锁 */

       pthread_mutex_lock(&m);

      

       sum += 400;

       printf("main thread + 400!\n");

      

       //拿完钱后,需要解锁

       pthread_mutex_unlock(&m);

      

       sleep(2);

      

       //唤醒所有的线程起来拿钱

       pthread_cond_broadcast(&v); //2个拿到钱,还有1个因为拿不到钱再回去睡觉。

       printf("broarcast!\n");

      

       sleep(3);

      

       pthread_mutex_lock(&m);

      

       sum += 200;

       printf("main thread + 200!\n");

      

       //拿完钱后,需要解锁

       pthread_mutex_unlock(&m);

      

       pthread_cond_signal(&v);

       printf("signal!\n");

      

       for(i=0;i<5;i++)

       {

              pthread_join(tid[i],NULL);

       }

      

       pthread_mutex_destroy(&m);

       pthread_cond_destroy(&v);

      

       return 0;

}

标签:rwlock,15,int,cond,2019,pthread,mutex,NULL,星期四
来源: https://www.cnblogs.com/zjlbk/p/11359558.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有