头文件 account.h
#ifndef __ACCOUNT_H__
#define __ACCOUNT_H__
//银行账户结构体
typedef struct{
int code;//卡号
double balance;//余额
}Account;
//创建账户
extern Account* creat_account(int code,double balance);
//销毁账户
extern void destory_account(Account *a);
//取款
extern double withdraw(Account *a,double amt);
//存款
extern double deposit(Account *a,double amt);
//查看账户余额
extern double get_balance(Account *a);
#endif
功能文件account.c
#include "account.h"
#include
#include
#include
//创建账户
Account* creat_account(int code,double balance){
//创建账户在堆当中
Account *a = (Account*)malloc(sizeof(Account));
assert(a != NULL);//用来判断a指针所需要开辟的空间,开辟成功了吗,成功就继续,否则就程序终止运行。
a->code = code;
a->balance = balance;
return a;
}
//销毁账户
void destory_account(Account *a){
assert(a != NULL);
free(a);//释放空间
}
//取款
double withdraw(Account *a,double amt){
if(amt < 0 || amt > a->balance){
return 0.0;
}
double balance = a->balance;
sleep(1);
balance -= amt;
a->balance = balance;
return amt;
}
//存款
double deposit(Account *a,double amt){
assert(a != NULL);
if(amt < 0){
return 0.0;
}
double balance = a->balance;
sleep(1);
balance += amt;
a->balance = balance;
return amt;
}
//查看账户余额
double get_balance(Account *a){
assert(a != NULL);
double balance = a->balance;
return balanec;
}
执行文件 account_test.c
#include "account.h"
#include
#include
#include
#include
//操作者的结构体
typedef struct{
char name[20];//操作者姓名
Account *account;//账户
double amt;//金额
}OperArg
//定义取款操作的线程运行函数
void* withdraw_fn(void *arg){
OperArg *oa = (OperArg*)arg;
//deposit存款函数
double amt = deposit(oa->account,oa->amt);
printf("%8s(0x%lx) deposit %f from account %d/n",oa->name,pthread_self(),amt,oa->account->code);
return (void*)0;
}
//定义存款操作的线程运行函数
void* deposit_fn(void *arg){
OperArg *oa = (OperArg*)arg;
//withdraw取款函数
double amt = withdraw(oa->account,oa->amt);
printf("%8s(0x%lx) withdraw %f from account %d/n",oa->name,pthread_self(),amt,oa->account->code);
return (void*)0;
}
//定义查看银行账户的线程运行函数
void* check_fn(void *arg){
}
int main(void){
int err;
pthread_t boy,girl;
Account *a = create_account(10001,10000)//卡号,余额
OperArg o1 , o2;//两个操作者
strcpy(o1.name,"boy");//strcpy()把第二个参数值,放到第一个参数中
o1.account = a;
o1.amt = 10000;
strcpy(o2.name,"girl");
o2.account = a;
o2.amt = 10000;
//启动两个子线程(boy和girl)同时去操作同一个银行账户
if((err = pthread_create(&boy,null,withdraw_fn,(void*)&o1)!=0){
printf("pthread create error");
}
if((err = pthread_create(&girl,null,withdraw_fn,(void*)&o2)!=0){
printf("pthread create error");
}
pthread_join(boy,null);
pthread_join(girl,null);
//查看账户余额
printf("account balance %f/n",get_balance(a));
//销毁账户
destroy_account(a);
return 0;
}
程序输出结果:

girl和boy都从银行账户10001中取出了10000元,所以产生了错误。
//锁的定义
pthreat_mutex_t mutex;
//锁的初始化
int pthread_mutex_init(pthread_mutex_t *restrict mutex,const pthreat_mutex_t *mutexattr);
//锁的销毁
int pthread_mutex_destroy(pthreat_mutex_t *mutex);
返回:成功返回 0 否则返回错误编号
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 出错返回出错码
头文件 account.h
#ifndef __ACCOUNT_H__
#define __ACCOUNT_H__
#include
//银行账户结构体
typedef struct{
int code;//卡号
double balance;//余额
//定义一把互斥锁,用来对多线程操作
//银行账户(共享资源)进行加锁保护
/*
建议互斥锁和账户(共享资源)绑定一起,用来锁定一个账户(共享资源)
尽量不设置全局变量,否则肯能出现一把锁去锁几百个账户,导致并发性能降低
*/
pthread_mutex_t mutex;
}Account;
//创建账户
extern Account* creat_account(int code,double balance);
//销毁账户
extern void destory_account(Account *a);
//取款
extern double withdraw(Account *a,double amt);
//存款
extern double deposit(Account *a,double amt);
//查看账户余额
extern double get_balance(Account *a);
#endif
功能文件account.c
#include "account.h"
#include
#include
#include
//创建账户
Account* creat_account(int code,double balance){
//创建账户在堆当中
Account *a = (Account*)malloc(sizeof(Account));
assert(a != NULL);//用来判断a指针所需要开辟的空间,开辟成功了吗,成功就继续,否则就程序终止运行。
a->code = code;
a->balance = balance;
//对互斥锁进行初始化
pthread_mutex_init(&a->mutex,null);
return a;
}
//销毁账户
void destory_account(Account *a){
assert(a != NULL);
//销毁互斥锁
pthread_mutex_destroy(&a->mutex)
free(a);//释放空间
}
//取款
double withdraw(Account *a,double amt){
assert(a != NULL);//判断指针a是否为空
/*
从成功上锁,到释放锁之间对共享资源操作的区间称为临界区
*/
pthread_mutex_lock(&a->mutex);//对共享共享资源(账户)加锁
//有线程执行到此时,账户加锁,当其他线程执行到此时,就会被堵塞
if(amt < 0 || amt > a->balance){
//释放互斥锁
pthread_mutex_unlock(&a->mutex);
return 0.0;
}
double balance = a->balance;
sleep(1);
balance -= amt;
a->balance = balance;
//释放互斥锁
pthread_mutex_unlock(&a->mutex);
return amt;
}
//存款
double deposit(Account *a,double amt){
assert(a != NULL);
pthread_mutex_lock(&a->mutex)//对共享共享资源(账户)加锁
if(amt < 0){
//释放互斥锁
pthread_mutex_unlock(&a->mutex);
return 0.0;
}
double balance = a->balance;
sleep(1);
balance += amt;
a->balance = balance;
//释放互斥锁
pthread_mutex_unlock(&a->mutex);
return amt;
}
//查看账户余额
double get_balance(Account *a){
assert(a != NULL);
pthread_mutex_lock(&a->mutex)//对共享共享资源(账户)加锁
double balance = a->balance;
//释放互斥锁
pthread_mutex_unlock(&a->mutex);
return balanec;
}
执行文件 account_test.c
#include "account.h"
#include
#include
#include
#include
//操作者的结构体
typedef struct{
char name[20];//操作者姓名
Account *account;//账户
double amt;//金额
}OperArg
//定义取款操作的线程运行函数
void* withdraw_fn(void *arg){
OperArg *oa = (OperArg*)arg;
//deposit存款函数
double amt = deposit(oa->account,oa->amt);
printf("%8s(0x%lx) deposit %f from account %d/n",oa->name,pthread_self(),amt,oa->account->code);
return (void*)0;
}
//定义存款操作的线程运行函数
void* deposit_fn(void *arg){
OperArg *oa = (OperArg*)arg;
//withdraw取款函数
double amt = withdraw(oa->account,oa->amt);
printf("%8s(0x%lx) withdraw %f from account %d/n",oa->name,pthread_self(),amt,oa->account->code);
return (void*)0;
}
//定义查看银行账户的线程运行函数
void* check_fn(void *arg){
}
int main(void){
int err;
pthread_t boy,girl;
Account *a = create_account(10001,10000)//卡号,余额
OperArg o1 , o2;//两个操作者
strcpy(o1.name,"boy");//strcpy()把第二个参数值,放到第一个参数中
o1.account = a;
o1.amt = 10000;
strcpy(o2.name,"girl");
o2.account = a;
o2.amt = 10000;
//启动两个子线程(boy和girl)同时去操作同一个银行账户
if((err = pthread_create(&boy,null,withdraw_fn,(void*)&o1)!=0){
printf("pthread create error");
}
if((err = pthread_create(&girl,null,withdraw_fn,(void*)&o2)!=0){
printf("pthread create error");
}
pthread_join(boy,null);
pthread_join(girl,null);
//查看账户余额
printf("account balance %f/n",get_balance(a));
//销毁账户
destroy_account(a);
return 0;
}
程序运行结果:

//互斥锁属性的初始化
int pthread_mutexattr_init(pthread_mutexattr_t *attr);
//互斥锁属性的销毁
int pthread_mutexattr_destroy(pthread_mutexattr_t *attr)
//restrict用于限定和约束指针,表示这个指针只访问这块内存的唯一方式
//共享属性获取,pshared用于存放获取的共享属性
int pthread_mutexattr_getpshared(const pthread_mutexattr_t *restrict attr,int *restrict pshared);
//共享属性设置,pshared用于指定共享属性
int pthread_mutexattr_setpshared(const pthread_mutexattr_t *attr,int pshared);
返回:成功返回0,出错返回错误编号
//restrict用于限定和约束指针,表示这个指针只访问这块内存的唯一方式
//共享属性获取,pshared用于存放获取的共享属性
int pthread_mutexattr_gettype(const pthread_mutexattr_t *restrict attr,int *restrict type);
//共享属性设置,pshared用于指定共享属性
int pthread_mutexattr_settype(const pthread_mutexattr_t *attr,int type);
返回:成功返回0,出错返回错误编号
#include
#include
#include
#include
int main(int argc,char *argv[]){
//定义锁
pthread_mutex_t mutex;
if(argc<2){
printf("-usage:%s [error|normal|recursive]/n",argv[0]);
exit(1);
}
//定义互斥锁属性
pthread_mutexatte_t mutexattr;
//初始化互斥锁属性
pthread_mutexattr_init(&mutexattr);
/*
strcmp函数用于比较两个字符串并根据比较结果返回整数。
基本形式为strcmp(str1,str2),
若str1=str2,则返回零;
若str1str2,则返回正数。
*/
if(!strcmp(argv[1]),"error"){
//设置互斥锁类型---检错型
pthread_mutexattr_settype(&mutexattr,PTHREAD_MUTEX_ERRORCHECK);
}else if(!strcmp(argv[1],"normal")){
//设置互斥锁类型---标准型
pthread_mutexattr_settype(&mutexattr,PTHREAD_MUTEX_NORMAL);
}else if(!strcmp(argv[1],"recursive")){
//设置互斥锁类型---递归型
pthread_mutexattr_settype(&mutexattr,PTHREAD_MUTEX_RECURSIVE );
}
//锁的初始化,第一个参数传入锁,第二个参数可以指定,也可以传入锁的属性,
pthread_mutex_init(&mutex,&mutexattr)
//上锁
if(pthread_mutex_lock(&mutex) !=0){
printf("lock failure\n");
}else{
printf("lock sucess\n");
}
//第二次上锁
if(pthread_mutex_lock(&mutex) !=0){
printf("lock failure\n");
}else{
printf("lock sucess\n");
}
//上了两次锁,解锁两次
pthread_mutex_unlock(&mutex);
pthread_mutex_unlock(&mutex);
//销毁属性
pthread_mutexattr_destroy(&mutexattr);
}
程序运行结果:
选择normal,锁的类型是普通型,第一次上锁成功,第二次失败,程序阻塞
选择recursive,锁的类型是递归性,第一次上锁成功, 第二次也成功,只是内部计数。
选择error,锁的类型是检错型,第一次上锁成功,第二次失败,程序报错

