Linux多线程笔记二

本文主要是对线程的互斥部分做简单的笔记,记录实现线程互斥的基本代码。

线程互斥

线程互斥,指的是线程执行的相互排斥。
解决互斥的方法:

  1. 互斥锁
  2. 读写锁
  3. 线程信号量

线程同步

线程同步,指的是多个线程执行的互斥与先后的顺序。

解决同步的方式:

  1. 条件变量
  2. 线程信号量

实例代码,以银行取款为例,先看一个线程共享数据,数据不安全的实例:
account.h

#ifndef ACCOUNT_H
#define ACCOUNT_H
#endif


typedef struct {
  int code;
  double banlance;
}Account;


extern Account* create_account(int code, double banlance);
extern void free_account(Account* ant);
extern double deposit(Account* ant, double amt);
extern double withdrawal(Account* ant, double amt);
extern double get_banlance(Account* ant);

account.c

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

Account* create_account(int code, double banlance) {

  assert(banlance != 0);
  assert(code != 0);

  Account* ant = (Account*)malloc(sizeof(Account));
  if (ant == NULL) {
    perror("malloc error");
    exit(1);
  }

  ant->code = code;
  ant->banlance = banlance;

  return ant;

}



void free_account(Account* ant) {
  free(ant);
}

double deposit(Account* ant, double amt) {
  assert(ant != NULL);
  if (amt <= 0) {
    return 0.0;
  }

  double cur_banlance = ant->banlance;
  sleep(1);
  cur_banlance += amt;
  ant->banlance = cur_banlance;
  return amt;
}


double withdrawal(Account* ant, double amt) {
  assert(ant != NULL);
  if (amt <= 0) {
    return 0.0;
  }
  double cur_banlance = ant->banlance;
  if (cur_banlance < amt) {
    return 0.0;
  }
  sleep(1);
  cur_banlance -= amt;
  ant->banlance = cur_banlance;
  return amt;
}


double get_banlance(Account* ant) {
  assert(ant != NULL);
  return ant->banlance;
}


main.c

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


typedef struct {
  int number;
  int amt;
  Account* account;
}OperArgs;


void* withdraw_fn(void* args) {
  OperArgs* oa = (OperArgs*)args;

  double amt = withdrawal(oa->account, oa->amt);

  printf("thread %d: id is: %lu withdrawal %lf from account %d\n", 
    oa->number,
    pthread_self(), amt, oa->account->code);
  return (void*)0;
}




int main(int argc, char const *argv[])
{
  Account* ant_one = create_account(100, 10000.0);
  printf("from the beginning %lf\n", get_banlance(ant_one));

  OperArgs o1;
  o1.account = ant_one;
  o1.amt = 10000;
  o1.number = 1;

  OperArgs o2;
  o2.account = ant_one;
  o2.amt = 10000;
  o2.number = 2;

  pthread_t boy, girl;

  pthread_create(&boy, NULL, withdraw_fn, (void*)&o1);
  pthread_create(&girl, NULL, withdraw_fn, (void*)&o2);


  pthread_join(boy, NULL);
  pthread_join(girl, NULL);

  double cur_banlance = get_banlance(ant_one);
  printf("account number: %d cur_banlance is %lf\n", ant_one->code, cur_banlance);
  free_account(ant_one);

}

运行结果如下:

from the beginning 10000.000000
thread 2: id is: 123145571397632 withdrawal 10000.000000 from account 100
thread 1: id is: 123145570861056 withdrawal 10000.000000 from account 100
account number: 100 cur_banlance is 0.000000

这段代码是一个线程不安全的代码,boy和girl两个线程都会去取钱,而且都取钱成功,需要改进,这里使用互斥锁进行改进。

互斥锁

互斥锁mutex是一种简单的加锁方法,用来控制对共享资源的访问。
同一时刻只能有一个线程掌握互斥锁,拥有上锁资源的线程才能对共享资源进行访问。
其他想要访问共享资源的线程会被挂起,直到互斥锁释放。

互斥锁的数据类型为
pthread_mutex_t
定义如下:

typedef union
{
  struct __pthread_mutex_s __data;
  char __size[__SIZEOF_PTHREAD_MUTEX_T];
  long int __align;
} pthread_mutex_t; 

为账号加锁,用来解决线程不安全问题

account.h

#ifndef ACCOUNT_H
#define ACCOUNT_H
#endif


typedef struct {
    int code;
    double banlance;
    
    // 互斥锁加在一个账户上,而不是全局变量
    // 不然会导致并发性能降低
    pthread_mutex_t lock;
}Account;


extern Account* create_account(int code, double banlance);
extern void free_account(Account* ant);
extern double deposit(Account* ant, double amt);
extern double withdrawal(Account* ant, double amt);
extern double get_banlance(Account* ant);

account.c

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

Account* create_account(int code, double banlance) {
    
    assert(banlance != 0);
    assert(code != 0);
    
    Account* ant = (Account*)malloc(sizeof(Account));
    if (ant == NULL) {
        perror("malloc error");
        exit(1);
    }
    
    ant->code = code;
    ant->banlance = banlance;
    
    //初始化互斥锁
    pthread_mutex_init(&ant->lock, NULL);
    return ant;
}



void free_account(Account* ant) {
    assert(ant != NULL);
    // 销毁互斥锁
    pthread_mutex_destroy(&ant->lock);
    free(ant);
}


double deposit(Account* ant, double amt) {
    assert(ant != NULL);
    // 对共享资源加锁
    pthread_mutex_lock(&ant->lock);
    if (amt <= 0) {
        // 释放锁
        pthread_mutex_unlock(&ant->lock);
        return 0.0;
    }
    
    double cur_banlance = ant->banlance;
    sleep(1);
    cur_banlance += amt;
    ant->banlance = cur_banlance;
    // 释放锁
    pthread_mutex_unlock(&ant->lock);
    return amt;
}


double withdrawal(Account* ant, double amt) {
    assert(ant != NULL);
    // 对共享资源加锁
    pthread_mutex_lock(&ant->lock);
    
    if (amt <= 0) {
        // 释放锁
        pthread_mutex_unlock(&ant->lock);
        return 0.0;
    }
    double cur_banlance = ant->banlance;
    if (cur_banlance < amt) {
        return 0.0;
    }
    sleep(1);
    cur_banlance -= amt;
    ant->banlance = cur_banlance;
    // 释放锁
    pthread_mutex_unlock(&ant->lock);
    return amt;
}


double get_banlance(Account* ant) {
    assert(ant != NULL);
    return ant->banlance;
}



main.c:

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


typedef struct {
    int number;
    int amt;
    Account* account;
}OperArgs;


void* withdraw_fn(void* args) {
    OperArgs* oa = (OperArgs*)args;
    
    double amt = withdrawal(oa->account, oa->amt);
    
    printf("thread %d: id is: %lu withdrawal %lf from account %d\n",
           oa->number,
           pthread_self(), amt, oa->account->code);
    return (void*)0;
}




int main(int argc, char const *argv[])
{
    Account* ant_one = create_account(100, 10000.0);
    printf("from the beginning %lf\n", get_banlance(ant_one));
    
    OperArgs o1;
    o1.account = ant_one;
    o1.amt = 10000;
    o1.number = 1;
    
    OperArgs o2;
    o2.account = ant_one;
    o2.amt = 10000;
    o2.number = 2;
    
    pthread_t boy, girl;
    
    pthread_create(&boy, NULL, withdraw_fn, (void*)&o1);
    pthread_create(&girl, NULL, withdraw_fn, (void*)&o2);
    
    
    pthread_join(boy, NULL);
    pthread_join(girl, NULL);
    
    double cur_banlance = get_banlance(ant_one);
    printf("account number: %d cur_banlance is %lf\n", ant_one->code, cur_banlance);
    free_account(ant_one);
    
}

运行结果:

from the beginning 10000.000000
thread 1: id is: 123145474289664 withdrawal 10000.000000 from account 100
thread 2: id is: 123145474826240 withdrawal 0.000000 from account 100
account number: 100 cur_banlance is 0.000000
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值