线程和进程延续

1.线程和进程启动终止方式 

1.创建子进程,子线程       

2.退出进程/线程

3.回收僵尸进程资源 / 回收线程资源

4.进程终止函数  /  线程清理函数

2.线程状态切换

pthread_create()变为就绪态,调度后成为运行态,pthread_join()成为阻塞态,从运行态运行完或者异常退出后进入线程结束

3.线程属性初始化和销毁

最重要的是线程分离状态属性,其他系统会根据调度自己设置

使用线程属性前,需要初始化,结束再销毁

1.设置和获得分离属性

1.detach(分离)  第一个函数是获得当前线程属性中的分离属性,第二个是设置线程的分离状态属性   

2. detachstate取值为PTHREAD_CREATE_JOINABLE  要在主线程调用pthread_join()系统资源才会释放

3.以分离状态启动的线程,在线程结束后会自动释放占有的系统资源

4.线程启动分离属性编程实战

pthread_join(id,  &)用于释放线程结束前相关资源

1.以正常状态启动需要调用pthread_join()

2.以分离状态启动线程不要调用pthread_join(),会出错,也不能利用这个函数获取子线程运行函数返回结果,分离的意思是主控线程于子线程分离开了

3.分离属性在网络通讯中使用的多,例如服务器要响应几百个客户端请求,启动很多个进程不合适,在服务器端启动多线程来处理服务器端的大并发客户端请求,来一个处理一个,处理完了自动释放资源。在服务器端如何如理客户端多并发处理请求,启动线程以分离状态启动,这是最优的方式

5.线程前章节回顾

6.线程同步和互斥

1.线程互斥

在全局变量使用,例如存款,一个线程存钱100万,还没存入被另外一个线程将存款金额修改为一万,这样导致存入只有一万,这样就涉及线程不安全,一个线程对共享资源操作时,其他线程就等待,其他线程按照系统优先级调度对共享资源进行访问和操作,这样是互斥的操作,线程的互斥,线程的执行是相互排斥的

利用以下技术达到线程互斥

2.线程同步

建立在线程互斥基础上,但也要考虑线程先后执行约束问题,后面线程必须等待前一个线程操作完毕,结果出来后,后面线程才能对这个结果进行操作

研发小组进行软件开发,测试小组对软件项目进行测试,类似两个线程,研发小组对软件开发好后,再对软件进行测试,这里包含线程互斥,包含线程相互执行的约束,等到研发小组对软件开发好后,测试小组再对共享资源进行操作,测试小组严重依赖与研发小组

3.线程互斥案例(银行ATM操作)

堆中

3.线程互斥锁(互斥量)

多个线程共享资源的场景使用,电话亭,进入电话亭打电话锁住(打完后开门其他人根据先后再进入)    同一时刻只能有一个线程拿到该锁     一个线程对共享资源加锁,其他线程视图上锁已经被锁的资源,将被挂起,直到拿到锁的线程解锁

互斥锁数据类型pthread_muxtex_t

互斥锁的创建和销毁

1.互斥锁初始化函数第二个参数,传入NULL,以默认的情况下创建默认互斥锁,是个标准互斥锁,所以一般情况下传入NULL就行

互斥锁上锁和解锁

pthread_mutex_lock()上锁,拿不到锁阻塞

pthread_mutex_trylock(),上锁,拿不到锁返回错误

对共享资源成功上锁到释放锁之间的区域叫做临界区

结构体中定义互斥锁与银行账户绑定

typedef struct{
    int code;  //账户账号
    double balance;

    //定义一把互斥锁
    //银行账户(共享资源),互斥锁

    /*
        建议互斥锁用来锁定一个账户,和账户绑定在一起,
        尽量不设置成全局变量,否则
        可能出现一把锁去锁几百个账户,导致并发性能降低
    */
    pthread_mutex_t mutex;
}Account;

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 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 <malloc.h>
#include <assert.h>
#include <string.h>
#include <unistd.h>

//创建账户
Account* create_account(int code, double balance)
{
    //创建在堆中
    Account *a = (Account*)malloc(sizeof(Account));
    assert(a != NULL);  //()里面为bool类型,为假程序会就此结束
    a->code = code;
    a->balance = balance;

    //对互斥锁进行初始化
    pthread_mutex_init(&a->mutex, NULL);

    return a;
}
//销毁账户
void destroy_account(Account *a)
{
    assert(a != NULL);
    //销毁互斥锁
    pthread_mutex_destroy(&a->mutex);

    free(a);
}
//取钱
double withdraw(Account *a, double amt)
{
    assert(a != NULL);

    //从成功上锁到释放锁叫做临界区
    //加锁,对共享资源(账户)进行加锁,资源被占用则会阻塞
    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)用来使这个线程延时让其他线程占用CPU取款,模拟情景
    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;
    }
    a->balance += amt;
    sleep(1);

    //解锁
    pthread_mutex_unlock(&a->mutex);
    
    return amt;
}
//查看账户余额
double get_balance(Account *a)
{
    assert(a != NULL);

    //上锁
    pthread_mutex_lock(&a->mutex);

     //解锁
    pthread_mutex_unlock(&a->mutex);

    return (a->balance);
}

account_test.c代码

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

typedef struct{
    char name[20];   //名字
    Account *account;  //账户
    double amt;   //存取款金额
}OperArg;   //操作参数


//定义取款操作的线程运行函数
void*   withdraw_fn(void *arg)
{
    OperArg *oa = (OperArg*)arg;
    //取钱的账户和金额,取款失败返回0
    double amt = withdraw(oa->account, oa->amt);
    printf("%s(0x%lx) withdraw %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;
    //存钱的账户和金额
    double amt = deposit(oa->account, oa->amt);
    printf("%s(0x%lx) withdraw %f from account %d\n",
        oa->name, pthread_self(),
         amt, 
        oa->account->code);

    return (void*)0;

}

//定义检查银行账户的线程运行函数
void*   check_fn(void *arg)
{
    OperArg* oa = (OperArg*)arg;

    double balance;
    balance = get_balance(oa->account);
    printf("balance %f", balance);

    return (void*)0;
}

int main(void)
{
    int err;
    pthread_t boy, girl;
    //第一个是账户编码号,第二个是余额
    //这里两个线程的账户都初始化为a
    Account *a = create_account(100001, 10000); 

    OperArg o1, o2;  //传入不同线程运行函数中
    strcpy(o1.name, "boy");
    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)
    {
        perror("pthread create error");
    }
    if((err = pthread_create(&girl, NULL, withdraw_fn, (void*)&o2)) != 0)
    {
        perror("pthread create error");
    }
    pthread_join(boy, NULL);
    pthread_join(girl, NULL);

    //
    printf("account balance: %f\n", get_balance(a));
    destroy_account(a); //销毁账户


    return 0;
}

gcc运行编译结果

ji@ji-VM:~/c/pthread/account$ gcc account.c account_test.c 
ji@ji-VM:~/c/pthread/account$ ./a.out 
boy(0x7a8183200640) withdraw 10000.000000 from account 100001
girl(0x7a8182800640) withdraw 0.000000 from account 100001
account balance: 0.000000
ji@ji-VM:~/c/pthread/account$ 

4.互斥锁属性创建和销毁

互斥锁属性创建传入NULL则是创建标准互斥锁

5.设置和获取互斥锁进程共享属性

7.互斥锁类型操作

互斥锁初始化的时候

lockattr.c的代码,验证多次上锁同一互斥锁时,各种互斥锁属性对应的反应

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

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_mutexattr_t mutexattr;
    //初始化互斥锁属性
    pthread_mutexattr_init(&mutexattr);

    //字符串比较函数strcmp(),字符串相等返回0
    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 success\n");
    }

    //上锁第二次,用于模拟第二次
    //上锁面对不同互斥锁属性
    if(pthread_mutex_lock(&mutex) != 0){
        printf("lock failure\n");
    }else{
        printf("lock success\n");
    }

    //释放锁
    pthread_mutex_unlock(&mutex);
    
    return 0;
}

运行结果,正常锁第二次调用会阻塞,

8.线程互斥——读写锁

1.线程使用互斥锁缺乏读并发性

2.读写锁创建和销毁

3.读写锁加锁和解锁

pthread_rwlock_rdlock()   //加读锁

pthread_rwlock_wrlock()//加写锁

rwlock.c上读锁,写锁多次案例

1.读和读不排斥;

2.写和写排斥;

3.读和写排斥;

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

//定义读写锁
pthread_rwlock_t rwlock;

int main(int argc, char *argv[])
{
    if(argc < 3){
        printf("-usage:%s [r|w] [r|w]\n", argv[0]);
        exit(1);
    }

    //读写锁初始化
    pthread_rwlock_init(&rwlock, NULL);

    if(!strcmp(argv[1], "r")){
        //加读锁
        if(pthread_rwlock_rdlock(&rwlock) != 0){
            printf("first read lock failure\n");
        }else{
            printf("first read lock success\n");
        }
    }else if(!strcmp(argv[1], "w")){
        //加写锁
        if(pthread_rwlock_wrlock(&rwlock) != 0){
            printf("first write lock failure\n");
        }else{
            printf("first write lock success\n");
        }
    }

    if(!strcmp(argv[2], "r")){
        //加读锁
        if(pthread_rwlock_rdlock(&rwlock) != 0){
            printf("second read lock failure\n");
        }else{
            printf("second read lock success\n");
        }
    }else if(!strcmp(argv[2], "w")){
        //加写锁
        if(pthread_rwlock_wrlock(&rwlock) != 0){
            printf("second write lock failure\n");
        }else{
            printf("second write lock success\n");
        }
    }

    //解锁,释放读写锁
    pthread_rwlock_unlock(&rwlock);
    pthread_rwlock_unlock(&rwlock);

    //摧毁读写锁
    pthread_rwlock_destroy(&rwlock);

    return 0;
}

用读写锁解决银行取钱和存钱和查看余额之间的互斥利害

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值