zoukankan      html  css  js  c++  java
  • 多线程互斥锁、读写锁

    /*Linux环境编程:从应用到内核*/
    /*
    0.4.3 线程安全
    线程安全,顾名思义是指代码可以在多线程环境下“安全”地执行。何为安全?即符合正确的逻辑结果,是程序员
    期望的正常执行结果。为了实现线程安全,该代码要么只能使用局部变量或资源,要么就是利用锁等同步机制,来
    实现全局变量或资源的串行访问。
    
    6.1信号的完整声明周期
    信号的本质是一种进程间的通信。进程之间约定好:如果发生了某件事情T(trigger),就向目标进程(destination
     process)发送某特定信号X,而目标进程看到X,就意识到T事件发生了,目标进程就会执行相应的动作A(action)。
    
    总结:Linux的signal机制是一种原始的进程间通信机制,传递信息有限,很难传递复杂的消息,加上信号处理函数和
    进程处于两条执行逻辑流,会带来函数的重入问题,因此signal机制不适合作为进程间通信的主要手段。但是
    信号又不是完全无用的,对于某些不频繁发生的异步事件,还是可以使用signal来通知进程。 
    */
    
    /*
    7 理解linux线程
    
    设计多线程的原因:
    发挥多核优势,充分利用CPU资源
    更自然的编程模型:很多程序,天生就适合用多线程。将工作切分成多个模块,并为每个模块分配一个或多个
    执行单元,更符合人类解决问题的思路。
    
    多线程存在的弊端:
    多个线程之中,只要有一个线程不够健壮存在bug(如访问了非法地址引发的段错误),就会导致进程内的所有
    线程一起完蛋。
    线程模型作为一种并发的编程模型,效率并没有想象的那么高,会出现复杂度高、易出错、难以测试和定位问题。
    
    多线程之间存在负载均衡的问题;
    多个线程之间需要同步:若多个线程操作共享资源,则需要同步;因此多线程编程中存在临界区的概念,临界区
    的代码只允许一个线程执行,线程提供了锁机制来保护临界区。当其他线程来到临界区却无法申请到锁时,就可能
    陷入阻塞,不再处于可执行状态。
    
    有人曾经这样打比方:“多进程属于立体交通系统,虽然造价高,上坡下坡比较耗油,但是堵车少;多线程属于平面
    交通系统,造价低,但是红绿灯太多,老堵车”。
    
    表7-4 POSIX线程库的接口
    POSIX函数                           函数功能描述
    pthread_create                  创建一个线程
    pthread_exit                    退出线程
    pthread_self                    获取线程ID
    pthread_equal                   检查两个线程ID是否相等
    pthread_join                    等待线程退出
    pthread_detach                  设置线程状态为分离状态
    pthread_cancel                  线程的取消
    pthread_cleanup_push/pthread_cleanup_pop  线程退出,清理函数注册和执行   
    
    线程创建销毁的流程
    Main Thraed->pthread_ceate()->Thread->pthread_exit()->pthread_join()->exit()
    不连接(pthread_join)已经退出的线程,会导致资源无法释放。
    
    互斥量
    为什么需要互斥量? 大部分情况下,线程使用的数据都是局部变量,变量的地址在线程栈空间内,这种情况下,
    变量归属于单个线程,其他线程无法获取这种变量。
    但实际情况是,很多变量都是多个线程共享的,这样的变量称为共享变量。可通过数据的共享,完成多个线程之间
    的交互。
    */
    //多线程及互斥锁代码
    #define _GNU_SOURCE
    #include <stdio.h>
    #include <stdlib.h>
    #include <unistd.h>
    #include <pthread.h>
    #include <string.h>
    #include <errno.h>
    #include <sys/types.h>
    #define LOOP_TIMES 10000000
    #define NR_THREAD 4
    pthread_rwlock_t rwlock;
    pthread_mutex_t mutex;
    int global_cnt = 0; //共享变量
    void* thread_work(void* param)
    {
        int i;
        pthread_rwlock_rdlock(&rwlock);
        for(i=0; i < LOOP_TIMES; i++)
        {
            pthread_mutex_lock(&mutex);     //互斥量加锁
            global_cnt++;
            pthread_mutex_unlock(&mutex);   //互斥量关锁
        }
        pthread_rwlock_unlock(&rwlock);
        return NULL;
    }
    int main(int argc, char* argv[])
    {
        pthread_t tid[NR_THREAD];
        char err_buf[1024];
        int i, ret;
        ret=pthread_rwlock_init(&rwlock, NULL);     //读写锁
        if(ret)
        {
            fprintf(stderr, "init rw lock failed (%s)
    ", strerror_r(ret, err_buf, sizeof(err_buf)));
            exit(1);
        }
        ret=pthread_mutex_init(&mutex, NULL);
        if(ret)
        {
            fprintf(stderr, "init mutex lock failed (%s)
    ", strerror_r(ret, err_buf, sizeof(err_buf)));
            exit(1);
        }
        pthread_rwlock_wrlock(&rwlock);
        for(i=0; i<NR_THREAD; i++)
        {
            ret = pthread_create(&tid[i], NULL, thread_work, NULL);
            if(ret != 0)
            {
                fprintf(stderr, "create thread failed, return %s
    ", 
                                strerror_r(ret, err_buf, sizeof(err_buf)));
                exit(1);
            }
        }
        pthread_rwlock_unlock(&rwlock);     //子线程创建完成,主线程的读写锁关闭,4个线程同时启动
        for(i=0; i<NR_THREAD; i++)
        {
            pthread_join(tid[i], NULL);     //等待所有线程任务完成;
        }
        pthread_mutex_destroy(&mutex);
        pthread_rwlock_destroy(&rwlock);
        printf("threadnum:  %d
    ",NR_THREAD);
        printf("loops per thrad: %d
    ",LOOP_TIMES);
        printf("expect result: %d
    ", LOOP_TIMES*NR_THREAD);
        printf("actual result: %d
    ", global_cnt);
        exit(0);
    }
    /*
    注意事项:
    1.编译方法:gcc mutex.c -o mutex  -lpthread
    pthread 库不是 Linux 系统默认的库,连接时需要使用静态库 libpthread.a
    所以在使用pthread_create()创建线程,及pthread_rwlock*读写锁,处理程序时,需要链接该库
    2.互斥量和读写锁使用完成后都要手动销毁
    */
    
    /*
    7.8读写锁
    很多时候,对共享变量的访问有以下特点:大多数情况下线程只是读取共享变量的值,并不修改,只有极少数情况下,线程才会真正的修改共享变量的值。
    对于这种情况,读请求之间是无需同步的,它们之间的并发访问是安全的。然而写请求必须锁住读请求和其他请求。
    这种情况在实际中是存在的,比如配置项。大多数时间内,配置是不会发生变化的,偶尔会出现修改配置的情况。如果使用互斥量,完全阻止请求并发,则会
    造成性能损失。
    */
  • 相关阅读:
    存储过程
    C++学习总结
    Android快速开发系列 10个常用工具类
    SimpleHttpServer的学习之总体架构
    SimpleHttpServer的学习之UML
    SimpleHttpServer的学习(1)
    map用法
    idea 中resources下于java包名相同的包不能导入XML文件问题
    leetcode621
    Yukari's Birthday 枚举+二分 过程注意数据的溢出问题 HDU4430
  • 原文地址:https://www.cnblogs.com/go-ahead-wsg/p/13336288.html
Copyright © 2011-2022 走看看