线程实际运行过程中,我们经常需要多个线程保持同步。这时可以用互斥锁来完成任务;互斥锁的使用过程中,主要有pthread_mutex_init,pthread_mutex_destory,pthread_mutex_lock,pthread_mutex_unlock四个函数。
int pthread_mutex_init(pthread_mutex_t *restrict mutex, const pthread_mutexattr_t *restrict attr);
该函数用于C函数的多线程编程中,互斥锁的初始化。
pthread_mutex_init()函数是以动态方式创建互斥锁的,参数attr指定了新建互斥锁的属性。如果参数attr为NULL,则使用默认的互斥锁属性,默认属性为快速互斥锁 。互斥锁的属性在创建锁的时候指定,在LinuxThreads实现中仅有一个锁类型属性,不同的锁类型在试图对一个已经被锁定的互斥锁加锁时表现不同。
pthread_mutexattr_init()函数成功完成之后会返回零,其他任何返回值都表示出现了错误。
函数成功执行后,互斥锁被初始化为锁住态。
int pthread_mutex_lock(pthread_mutex_t *mutex)
int pthread_mutex_unlock(pthread_mutex_t *mutex)
int pthread_mutex_trylock(pthread_mutex_t *mutex)
pthread_mutex_trylock()语义与pthread_mutex_lock()类似,不同的是在锁已经被占据时返回EBUSY而不是挂起等待。
实验:创建两条线程,线程的执行函数是取钱,(这里采用了互斥锁的功能,就解决了上一节介绍的访问共享资源出现的问题),本实验有3个文件,其中account.c 和 account.h 文件是模拟银行取钱,存钱,查询余额的函数,test.c为主函数。
tips:这里的互斥锁是一个局部变量,尽量少的定义成全局变量
源码如下:
account.h
/****************************/
#ifndef __ACCOUNT_H__#define __ACCOUNT_H__#include <pthread.h>typedef struct{ int code; double balance; pthread_mutex_t mutex;}Account;extern Account * create_account(int code,double balance);extern void destroy_account(Account *a);extern double with_draw(Account *a,double amt);extern double depoist(Account *a,double amt);extern double get_balance(Account *a)#endif
/****************************/
account.c
#include "account.h"#include <assert.h>#include <malloc.h>#include <string.h>Account *create_account(int code, double balance){ Account *r=(Account *)malloc(sizeof(Account)); assert(r!=NULL); r->code=code; r->balance=balance; pthread_mutex_init(&r->mutex,NULL); return r;}void destroy_account(Account *a){ assert(a!=NULL); free(a);}double with_draw(Account *a, double amt){ assert(a!=NULL); pthread_mutex_lock(&a->mutex); if(amt > a->balance || amt<0){ pthread_mutex_unlock(&a->mutex); return 0.0; } double balance=a->balance; sleep(1); balance = balance - amt;
a->balance = balance;
pthread_mutex_unlock(&a->mutex);
return amt;}double depoist(Account *a, double amt){ assert(a!=NULL); if(amt<0){ return 0.0; } pthread_mutex_lock(&a->mutex); double balance=a->balance; sleep(1); balance = balance + amt; a->balance = balance; pthread_mutex_unlock(&a->mutex); return amt;
}
/************************************/
test.c
/*********************************/
#include <pthread.h>#include <stdio.h>#include <stdlib.h>#include <string.h>#include <unistd.h>#include "account.h"typedef struct{ char name[20]; Account *account; double amt;}Arg;void *func_th(void *arg){ Arg *r=(Arg *)arg; double amt=with_draw(r->account,r->amt); printf("%8s(0x%lx) withdraw %f from account %d\n", r->name,pthread_self(),amt,r->account->code); return (void*)0;}int main(int argc,char *argv[]){ int err; pthread_t boy,girl; Account *a=create_account(1001,10000); Arg r1,r2; strcpy(r1.name,"man"); r1.account=a; r1.amt=10000; strcpy(r2.name,"woman");
r2.account=a;
r2.amt=10000; if((err=pthread_create(&boy,NULL,func_th,(void *)&r1))!=0) { perror("pthread create error"); } if((err=pthread_create(&girl,NULL,func_th,(void *)&r2))!=0) { perror("pthread create error"); } pthread_join(boy,NULL); pthread_join(girl,NULL); //打印余额 printf("the rest of the count is %f\n",get_balance(a)); //打印线程ID printf("%lx thread finished\n",pthread_self()); return 0;
}
/****************************/
实验结果:
woman(0x7fd78cb2f700) withdraw 10000.000000 from account 1001 man(0x7fd78d330700) withdraw 0.000000 from account 1001the rest of the count is 0.0000007fd78db33700 thread finished
