Linux线程浅析[线程的同步和互斥之线程互斥锁]

Linux线程浅析[线程的同步和互斥]

  1. 线程同步
  2. 线程互斥
  3. 线程互斥的相关函数
  4. 线程同步的相关函数

线程同步

是宏观上的一个概念,在微观上面包含线程的相互排斥和线程的执行顺序的约束问题
解决方法:
    条件变量
    线程信号量

例子:一栋大楼的建造,包含了质监局的检验和工程队的施工,那么假设质监局和工程队是两个线程,而大楼则为共享资源,首先相互排斥的原则为工程队施工的时候,质监局是不能进行检验的,因为这个时候大楼还没有建好,而质监局的检验依赖于工程队施工的结果,所以质监局必须等待工程队将大楼建造好.所以后一个线程依赖于前一个线程对共享资源操作的结果.所以说线程同步是包含了相互排斥和线程的执行顺序.

线程互斥

线程的相互排斥
解决方法:
    互斥锁
    读写锁
    线程信号量

 例子:
 一个公用厕所,假设只有一个坑,那么很多人去上厕所的时候,后一个就必须等后一个上完厕所之后才能上厕所.所以同一时间只能有一个人上厕所.这就是互斥.其实在生活中有很多例子.如银行账户的操作问题.12306的售票问题等.都是互斥
 注意:同步包含了互斥,互斥仅仅只是相互排斥,而同步是互斥加顺序

 先来一段有问题的代码:两个线程同时去访问同一个账户的问题:
  account.h

/*
 * ===========================================================================
 *
 *       Filename:  account.h
 *    Description:  
 *        Version:  1.0
 *        Created:  2017年03月28日 22时04分18秒
 *       Revision:  none
 *       Compiler:  gcc
 *         Author:   (), 
 *        Company:  
 *
 * ===========================================================================
 */

#ifndef __ACCOUNT_H_
#define __ACCOUNT_H_
//声明银行账户的结构体
  typedef struct{
    int code;
    double balance;
  }Account;

//创建银行账户
extern Account* create_account(int code,double balance);

//销毁一个账户
extern void destory_account(Account* account);

//存款
extern double withdraw(Account* account,double amt);

//取款
extern double deposit(Account* a,double amt);

//查看账户余额
extern double get_balance(Account* account);

#endif

account.c

/*
 * ===========================================================================
 *
 *       Filename:  account.c
 *    Description:  
 *        Version:  1.0
 *        Created:  2017年03月30日 21时16分28秒
 *       Revision:  none
 *       Compiler:  gcc
 *         Author:   (), 
 *        Company:  
 *
 * ===========================================================================
 */

#include"account.h"
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<malloc.h>
#include<assert.h>
#include<pthread.h>
/* 
 *创建一个账户
 *返回这个账户的指针
 *
 * */
extern Account* create_account(int code,double balance){
    Account* account = (Account*)malloc(sizeof(Account));
    assert(account !=NULL);
    account->code = code;
    account->balance = balance;
    //初始化锁的过程
    return account;
}
/* *
 *销毁一个账户
 * */
extern void destory_account(Account* account){
   assert(account!=NULL);
   free(account);
}

/* *
 *取款,返回的是账户的余额
 *
 * */
extern double withdraw(Account * account,double amt){
  assert(account != NULL);
  if(amt < 0 || amt > account->balance){
    return 0.0;
  }
  int balance = account -> balance;
  sleep(1);
  int result = balance - amt;
  account ->balance = result;
  //pthread_mutex_unlock(&account->pthreadmutex);
  return amt;
}
/* *
 *存款,返回的也是账户的余额
 *
 * */
extern double deposit(Account* account,double amt){
   assert(account != NULL);
   if(amt < 0){
      return 0.0;
   }
   int result = account ->balance + amt;
   sleep(2);
   account->balance = result;
   return result;
}

/* *
 *获取的就是这个账户的余额
 *
 * */
extern double get_balance(Account* account){
  assert(account !=NULL);
  return account -> balance;
}

accountTest.c

/*
 * ===========================================================================
 *
 *       Filename:  accountTest.c
 *    Description:  
 *        Version:  1.0
 *        Created:  2017年03月30日 21时31分19秒
 *       Revision:  none
 *       Compiler:  gcc
 *         Author:   (), 
 *        Company:  
 *
 * ===========================================================================
 */

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<pthread.h>
#include"account.h"

typedef struct{
  char name[20];
  Account* account;
  double amt;
}ArgvType;

/* *
 *检查账户的函数
 * */
void* th_check(void *argv){
  ArgvType* argvType = (void*)argv;
  double balance = get_balance(argvType->account);
  printf("name:%s,balance:%f,pthread:%lx\n",argvType->name,balance,pthread_self());
  return (void*)0;
}

/* *
 *取款函数
 * */
void* th_withdraw(void *argv){
  ArgvType* argvType = (ArgvType*)argv;
  double balance = withdraw(argvType->account,argvType->amt);
  printf("name:%s,balance:%f,pthread:%lx\n",argvType->name,balance,pthread_self());
  return (void*)0;
}

/* *
 *存款函数
 * */
void* th_deposite(void *argv){
  ArgvType* argvType = (ArgvType*)argv;
  double balance = deposit(argvType->account,argvType->amt);
  printf("name:%s,balance:%f,pthread:%lx\n",argvType->name,balance,pthread_self());
  return (void*)0;
}

int main(int argc,char *argv[]){
  int result;
  pthread_t boyfriend,girlfriend;
  Account *account = create_account(10001,10000);
  ArgvType argv_typeboy,argv_typegirl;
  strcpy(argv_typeboy.name,"zhangsan");
  strcpy(argv_typegirl.name,"xiaoli");
  argv_typeboy.account = account;
  argv_typegirl.account = account;
  argv_typeboy.amt = 10000;
  argv_typegirl.amt = 10000;

  if((result = pthread_create(&boyfriend,NULL,th_withdraw,(void*)&argv_typeboy))!=0){
     perror("boythread create error");
     exit(EXIT_FAILURE);
  }
  if((result = pthread_create(&girlfriend,NULL,th_withdraw,(void*)&argv_typegirl))!=0){
    perror("girlthread create error");
    exit(EXIT_FAILURE);
  }

  pthread_join(boyfriend,NULL);
  pthread_join(girlfriend,NULL);
  printf("get_balance:%f\n",get_balance(account));
  printf("thread:%lx exe ended\n",pthread_self());



  return 0;
}

name:zhangsan,withdraw:10000.000000,balance:0.000000,pthread:7f34bf2a9700
name:xiaoli,withdraw:10000.000000,balance:0.000000,pthread:7f34beaa8700
get_balance:0.000000
thread:7f34bfa94740 exe ended

 输出的结果如下所示:
 从上面输出结果中我们可以看到,其实xiaoli和zhangsan都取到了10000,但是这中情况是及其不符合日常生活的逻辑的,而我们的线程互斥的目的也就是为了解决这样一种并发,即多个线程访问同一个共享资源的时候,怎么去进行处理,后面在此例子基础上面去做修改.

线程互斥的相关函数

互斥锁:

互斥锁是一种简单的加锁的方法来控制对共享资源的访问。在同一时刻只能有一个线程掌握某个互斥锁,拥有上锁状态的线程能够对共享资源的访问,若其他线程希望上锁一个已经被上了锁的资源,则该线程挂起,知道上锁的线程释放互斥锁为止;

互斥锁数据类型:pthread_mutex_t

#include<pthread.h>
int pthread_mutex_init(pthread_mutex_t *restrict mutex,const pthread_mutexattr_t *mutexattr);//初始化互斥锁
int pthread_mutex_destory(pthread_mutex_t * mutex);
//销毁互斥锁
返回:成功返回0,失败返回错误编号
参数:
    mutex:互斥锁
    mutexattr:互斥锁创建方式
        PTHREAD_MUTEX_INITIALIZER:创建快速互斥锁
        PTHREAD_RECERSIVE_MUTEX_INITIALIZER_NP:创建递归互斥锁
        PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP:创建检错互斥锁

互斥锁的加锁和释放锁的过程

#include<pthread.h>
int pthread_mutex_lock(pthread_mutex_t *mutex)
功能:上锁,拿不到锁的时候阻塞
int pthread_mutex_trylock(pthread_mutex_t *mutex)
功能:拿不到锁返回出错信息
int pthread_mutex_unlock(pthread_mutex_t *mutex)
功能:释放锁
返回:成功返回0,错误返回错误码
参数:mutex
一个共享资源绑定一把锁,
建议:定义在结构体中,尽量不设置成为全局变量,否则可能会出现一把锁去锁几百个账户,导致并发性的下降:
临界区:对共享资源进行加锁到释放锁的整个代码区域(从上锁开始到释放锁结束)

互斥锁的属性创建和销毁;

    #include<pthread.h>
    int pthread_mutexattr_init(pthread_mutexattr_t *attr);
    int pthread_mutexattr_destory(pthead_muteattr_t *attr);
    返回值:成功返回0,失败返回错误码

参数:
    attr:互斥锁属性

互斥锁的进程共享属性:

#include<pthread.h>

int pthread_mutexattr_getpshared(const pthread_mutexattr_t *restrict attr,int *restrict pshared)
int pthread_mutexattr_setpshared(pthread_mutexattr_t *attr,int pshared)
返回:成功返回0,失败返回错误编号
参数:
    attr:互斥锁属性
    pshared:进程共享属性
    PTHREAD_PROCESS_PRIVATE(默认)
        锁只能用于一个进程内部的两个线程进行互斥
    PTHREAD_PROCESS_SHARED
        锁能够用于两个不同进程中的线程进行互斥(跨进程)

一般情况下我们都是在同一个进程中去使用互斥锁

互斥锁的类型:

#include<pthread.h>
int pthread_mutexattr_gettype(const pthread_mutexattr_t *restrict attr,int *restrict type)
int pthread_mutexattr_settype(pthread_amutexattr_t *attr,int type)
参数
    attr 互斥锁属性
    type:互斥锁类型
        标准互斥锁:PTHREAD_MUTEX_NOMAL
            第一次上锁成功,第二次上锁失败
        递归互斥锁:PTHREAD_MUTEX_RECURSIVE
            第一次上锁成功,第二次上锁还是成功,内部计数
        检错互斥锁:PTHREAD_MUTEX_ERRORCHECK
            第一次上锁成功,第二次上错会出错
默认互斥锁:PTHREAD_MUTEX_DEFAULT(同标准互斥锁)

 先上一个简单的上锁的案例:,在上述基础上修改的

/*
 * ===========================================================================
 *
 *       Filename:  account.h
 *    Description:  
 *        Version:  1.0
 *        Created:  2017年03月28日 22时04分18秒
 *       Revision:  none
 *       Compiler:  gcc
 *         Author:   (), 
 *        Company:  
 *
 * ===========================================================================
 */

#ifndef __ACCOUNT_H_
#define __ACCOUNT_H_
//声明银行账户的结构体
//引用pthread头文件.方便后面加锁
#include<pthread.h>
  typedef struct{
    int code;
    double balance;
    //将锁声明在结构体中,有助于每一个这样的结构体都有一把锁,那么在操作的时候,有利于优化并发效果
    pthread_mutex_t pthreadmutex;
  }Account;

//创建银行账户
extern Account* create_account(int code,double balance);

//销毁一个账户
extern void destory_account(Account* account);

//存款
extern double withdraw(Account* account,double amt);

//取款
extern double deposit(Account* a,double amt);

//查看账户余额
extern double get_balance(Account* account);

#endif
/*
 * ===========================================================================
 *
 *       Filename:  account.c
 *    Description:  
 *        Version:  1.0
 *        Created:  2017年03月30日 21时16分28秒
 *       Revision:  none
 *       Compiler:  gcc
 *         Author:   (), 
 *        Company:  
 *
 * ===========================================================================
 */

#include"account.h"
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<malloc.h>
#include<assert.h>
#include<pthread.h>
/* 
 *创建一个账户
 *返回这个账户的指针
 *
 * */
extern Account* create_account(int code,double balance){
    Account* account = (Account*)malloc(sizeof(Account));
    assert(account !=NULL);
    account->code = code;
    account->balance = balance;
    //初始化锁的过程
    pthread_mutex_init(&account->pthreadmutex,NULL);
    return account;
}
/* *
 *销毁一个账户
 * */
extern void destory_account(Account* account){
   assert(account!=NULL);
   free(account);
   //销毁锁的过程
   pthread_mutex_destroy(&account->pthreadmutex);
}

/* *
 *取款,返回的是账户的余额
 *
 * */
extern double withdraw(Account * account,double amt){
  assert(account != NULL);
  //上锁的过程
  pthread_mutex_lock(&account->pthreadmutex);
  if(amt < 0 || amt > account->balance){
    //解锁的过程
    pthread_mutex_unlock(&account->pthreadmutex);
    return 0.0;
  }
  int balance = account -> balance;
  sleep(1);
  int result = balance - amt;
  account ->balance = result;
  //解锁的过程
  pthread_mutex_unlock(&account->pthreadmutex);
  return amt;
}
/* *
 *存款,返回的也是账户的余额
 *
 * */
extern double deposit(Account* account,double amt){
   assert(account != NULL);
   //上锁的过程
   pthread_mutex_lock(&account->pthreadmutex);
   if(amt < 0){
     //解锁的过程
    pthread_mutex_unlock(&account->pthreadmutex);
      return 0.0;
   }
   int balance = account ->balance;
   sleep(2);
   int result = balance + amt;
   account->balance = result;
   //解锁的过程
   pthread_mutex_unlock(&account->pthreadmutex);
   return result;
}

/* *
 *获取的就是这个账户的余额
 *
 * */
extern double get_balance(Account* account){
  assert(account !=NULL);
  return account -> balance;
}
/*
 * ===========================================================================
 *
 *       Filename:  accountTest.c
 *    Description:  
 *        Version:  1.0
 *        Created:  2017年03月30日 21时31分19秒
 *       Revision:  none
 *       Compiler:  gcc
 *         Author:   (), 
 *        Company:  
 *
 * ===========================================================================
 */

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<pthread.h>
#include"account.h"

typedef struct{
  char name[20];
  Account* account;
  double amt;
}ArgvType;

/* *
 *检查账户的函数
 * */
void* th_check(void *argv){
  ArgvType* argvType = (void*)argv;
  double balance = get_balance(argvType->account);
  printf("name:%s,balance:%f,pthread:%lx\n",argvType->name,balance,pthread_self());
  return (void*)0;
}

/* *
 *取款函数
 * */
void* th_withdraw(void *argv){
  ArgvType* argvType = (ArgvType*)argv;
  double balance = withdraw(argvType->account,argvType->amt);
  printf("name:%s,balance:%f,pthread:%lx\n",argvType->name,balance,pthread_self());
  return (void*)0;
}

/* *
 *存款函数
 * */
void* th_deposite(void *argv){
  ArgvType* argvType = (ArgvType*)argv;
  double balance = deposit(argvType->account,argvType->amt);
  printf("name:%s,balance:%f,pthread:%lx\n",argvType->name,balance,pthread_self());
  return (void*)0;
}

int main(int argc,char *argv[]){
  int result;
  pthread_t boyfriend,girlfriend;
  Account *account = create_account(10001,10000);
  ArgvType argv_typeboy,argv_typegirl;
  strcpy(argv_typeboy.name,"zhangsan");
  strcpy(argv_typegirl.name,"xiaoli");
  argv_typeboy.account = account;
  argv_typegirl.account = account;
  argv_typeboy.amt = 10000;
  argv_typegirl.amt = 10000;

  if((result = pthread_create(&boyfriend,NULL,th_withdraw,(void*)&argv_typeboy))!=0){
     perror("boythread create error");
     exit(EXIT_FAILURE);
  }
  if((result = pthread_create(&girlfriend,NULL,th_withdraw,(void*)&argv_typegirl))!=0){
    perror("girlthread create error");
    exit(EXIT_FAILURE);
  }

  pthread_join(boyfriend,NULL);
  pthread_join(girlfriend,NULL);
  printf("get_balance:%f\n",get_balance(account));
  printf("thread:%lx exe ended\n",pthread_self());



  return 0;
}

这里写图片描述
 输出的结果如上所示,这个时候其实取款的时候就已经没有并发情况再出现了

/*
 * ===========================================================================
 *
 *       Filename:  account.c
 *    Description:  
 *        Version:  1.0
 *        Created:  2017年03月30日 21时16分28秒
 *       Revision:  none
 *       Compiler:  gcc
 *         Author:   (), 
 *        Company:  
 *
 * ===========================================================================
 */

#include"account.h"
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<malloc.h>
#include<assert.h>
#include<pthread.h>

static pthread_mutexattr_t attr;
/* 
 *创建一个账户
 *返回这个账户的指针
 *
 * */
extern Account* create_account(int code,double balance){
    Account* account = (Account*)malloc(sizeof(Account));
    assert(account !=NULL);
    account->code = code;
    account->balance = balance;
    //初始化锁的过程
    pthread_mutexattr_init(&attr);
    pthread_mutexattr_settype(&attr,PTHREAD_MUTEX_NORMAL);
    //pthread_mutexattr_settype(&attr,PTHREAD_MUTEX_RECURSIVE);
    //pthread_mutexattr_settype(&attr,PTHREAD_MUTEX_ERRORCHECK);
    //pthread_mutex_init(&account->pthreadmutex,NULL);
    pthread_mutex_init(&account->pthreadmutex,&attr);
    return account;
}
/* *
 *销毁一个账户
 * */
extern void destory_account(Account* account){
   assert(account!=NULL);
   free(account);
   //销毁锁的过程
   pthread_mutexattr_destroy(&attr);
   pthread_mutex_destroy(&account->pthreadmutex);
}

/* *
 *取款,返回的是账户的余额
 *
 * */
extern double withdraw(Account * account,double amt){
  assert(account != NULL);
  //上锁的过程
  pthread_mutex_lock(&account->pthreadmutex);
  if(amt < 0 || amt > account->balance){
    //解锁的过程
    pthread_mutex_unlock(&account->pthreadmutex);
    return 0.0;
  }
  int balance = account -> balance;
  sleep(1);
  int result = balance - amt;
  account ->balance = result;
  //解锁的过程
  pthread_mutex_unlock(&account->pthreadmutex);
  return amt;
}
/* *
 *存款,返回的也是账户的余额
 *
 * */
extern double deposit(Account* account,double amt){
   assert(account != NULL);
   //上锁的过程
   pthread_mutex_lock(&account->pthreadmutex);
   if(amt < 0){
     //解锁的过程
    pthread_mutex_unlock(&account->pthreadmutex);
      return 0.0;
   }
   int balance = account ->balance;
   sleep(2);
   int result = balance + amt;
   account->balance = result;
   //解锁的过程
   pthread_mutex_unlock(&account->pthreadmutex);
   return result;
}

/* *
 *获取的就是这个账户的余额
 *
 * */
extern double get_balance(Account* account){
  assert(account !=NULL);
  return account -> balance;
}

 以上都是对c的pthread互斥锁做的一个相对比较简单的一些使用方法.有兴趣的可以copy下来run一下,因为我也是新手,写的不好的地方欢迎指出

欢迎持续访问博客

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值