当前位置: 首页 > news >正文

cytoscape网站开发网站推广效果如何

cytoscape网站开发,网站推广效果如何,阿里巴巴指数查询,一个完整的个人网站互斥的相关概念 共享资源:指多个进程或线程可以共同访问和操作的资源临界资源:被保护的共享资源就叫做临界资源临界区:每个线程内部,访问临界资源的代码,就叫做临界区互斥:任何时刻,互斥保证有…

互斥的相关概念

  • 共享资源:指多个进程或线程可以共同访问和操作的资源
  • 临界资源:被保护的共享资源就叫做临界资源
  • 临界区:每个线程内部,访问临界资源的代码,就叫做临界区
  • 互斥:任何时刻,互斥保证有且只有一个执行流进⼊临界区,访问临界资源,通常对临界资源起保护作用
  • 原子性:不会被任何调度机制打断的操作,该操作只有两态,要么完成,要么未完成。

一个不加保护的Demo

这里使用多个线程共同执行上面的方法,代码很简单。但是运行结果怎么出现了负数?等于0不就直接break了吗?

原因有以下两点

  • 代码if(XXXX)不是原子操作,ticketnum--也不是原子操作
  • 所有的线程在尽可能多的进行调度切换执行 --- 线程或者进程什么时候会切换?
    • a.时间片耗尽
    • b.更高优先级的进程要调度
    • c.通过sleep,从内核返回用户时,会进行时间片是否到达的检测,进而导致切换

当我们执行上述代码时,每个线程都要这样执行上面的逻辑,但cpu的寄存器只有一套,但是寄存器中的数据有多套,且数据为线程私有。由于ticketnum--操作不是原子的(即,将ticketnum的值移动到CPU,CPU做运算,再将结果写回内存。共三步)。当一个线程正走到以上逻辑的第二步时,正准备判断,此时这个线程被切换了,一旦被切换,当前线程在寄存器中数据都会保存下来,等在被切回来的时候,再恢复!

        当票数为1时,a线程会做判断,符合逻辑进入if,走到usleep语句;此时b线程也进来了,a将寄存器中的数据带走,此时b线程见到的票数也是1,b线程也符合逻辑,进入if,也会走到usleep;同样的c和d线程都会做以上线程的动作,都会进入if。当a过了usleep时间,会执行--操作(1.重读数据2.--数据3.写回数据),此时票数为0了,同样的b,c,d线程也会做--,因为它们已经进入了if中。最后就导致票数为-2的情况了。

互斥量mutex

在Linux中互斥量就是锁

要解决上述多线程并发引起的安全问题,我们只需在进入临界区之前加上一把锁,就可以完美解决。

 互斥量(锁)的相关接口

  • pthread_mutex_init: 初始化互斥锁。
int pthread_mutex_init(pthread_mutex_t *restrict mutex, const pthread_mutexattr_t *restrict attr);pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;// 使用宏值初始化(全局)

    mutex:指向要初始化的互斥锁对象的指针。

    attr:指定互斥锁属性的对象,如果传递NULL,则使用默认的互斥锁属性。

    pthread_mutex_init 函数若调用成功,会返回 0。若发生错误,会返回一个非零的错误码。

    • pthread_mutex_destroy: 销毁互斥锁。
    int pthread_mutex_destroy(pthread_mutex_t *mutex);
    
    • pthread_mutex_lock: 锁定互斥锁
    int pthread_mutex_lock(pthread_mutex_t *mutex);
    
    • pthread_mutex_unlock: 解锁互斥锁。
     int pthread_mutex_unlock(pthread_mutex_t *mutex);
    

    锁接口的使用

    全局锁

    // 定义一个全局锁
    pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
    int ticketnum = 10000; // 共享资源,临界资源void Ticket()
    {while (true){pthread_mutex_lock(&lock); // 加锁if (ticketnum > 0){usleep(1000);printf("get a new ticket, id: %d\n", ticketnum--);pthread_mutex_unlock(&lock);     // 解锁}else{pthread_mutex_unlock(&lock);     // 解锁break;}}
    }
    int main()
    {// 创建多线程的逻辑,调用Tichetreturn 0;
    }

     局部锁

    使用ThreadData接收参数,包括锁的接收,保证每一个线程都能看到同一把锁

    #include <iostream>
    #include <string>
    #include <pthread.h>
    #include <functional>
    #include <sys/types.h>
    #include <unistd.h>namespace ThreadModule
    {// 要传递的参数struct ThreadData{ThreadData(const std::string &name, pthread_mutex_t *lock_ptr): _name(name), _lock_ptr(lock_ptr){}std::string _name;pthread_mutex_t *_lock_ptr;};// 执行任务的方法using func_t = std::function<void(ThreadData*)>;// 线程状态-枚举enum class TSTATUS{NEW,RUNNING,STOP};class Thread{private:// 成员方法,具备this指针,置为static之后就不具备this指针了static void *Routine(void *args){// t就拿到了this指针Thread *t = static_cast<Thread *>(args);t->_status = TSTATUS::RUNNING;t->_func(t->_td); // 就可以执行相应的类内方法了return nullptr;}public:// 线程要执行的方法直接传进来Thread(const std::string &name, func_t func, ThreadData* td): _name(name), _func(func), _td(td), _status(TSTATUS::NEW), _joinable(true){}bool Start(){if (_status != TSTATUS::RUNNING){int n = ::pthread_create(&_tid, nullptr, Routine, this); // 将this指针通过参数传过去if (n != 0)return false;return true;}return false;}bool Stop(){if (_status == TSTATUS::RUNNING){int n = ::pthread_cancel(_tid);if (n != 0)return false;_status = TSTATUS::STOP;return true;}return false;}bool Join(){if (_joinable){int n = ::pthread_join(_tid, nullptr);if (n != 0)return false;_status = TSTATUS::STOP;return true;}return false;}std::string Name() { return _name; }~Thread() {}private:std::string _name; // 线程名字pthread_t _tid;    // 线程idbool _joinable;    // 是否是分离状态,默认不是func_t _func;      // 线程未来要执行的方法TSTATUS _status;   // 线程状态ThreadData* _td;   // 要传递的参数};
    }
    

    让每个线程都获取局部锁的地址,在每个线程在执行抢票逻辑的时候,将锁的地址传给加锁函数,就能实现局部加锁了。 

    #include "Thread.hpp"
    #include <vector>int ticketnum = 10000;
    void Ticket(ThreadModule::ThreadData *td)
    {while(true){pthread_mutex_lock(td->_lock_ptr);      // 加锁if(ticketnum > 0){// 抢票printf("get a new ticket, who get it: %s, id: %d\n", td->_name.c_str(), ticketnum--);pthread_mutex_unlock(td->_lock_ptr);// 解锁}else{pthread_mutex_unlock(td->_lock_ptr);// 解锁break;}}
    }
    #define NUM 4
    int main()
    {// 创建局部锁pthread_mutex_t mutex;pthread_mutex_init(&mutex, nullptr);// 创建线程对象std::vector<ThreadModule::Thread> threads;for(int i = 0;i < NUM; i++){std::string name = "thread-" + std::to_string(i+1);// 把锁的地址给到td对象ThreadModule::ThreadData *td = new ThreadModule::ThreadData(name, &mutex);// 之后在将td给到Threadthreads.emplace_back(name, Ticket, td);}// 启动线程for(int i = 0; i< NUM;i++)threads[i].Start();// 等待线程for(int i = 0; i< NUM;i++)threads[i].Join();// 释放锁pthread_mutex_destroy(&mutex);  return 0;
    }

    锁的相关问题

    1. 锁本身是全局的,那么锁也是共享资源!谁保证锁的安全?

            pthread_mutex:加锁和解锁被设计成为原子的了

    2. 如何看待锁呢?二元信号量就是锁!

            2.1 加锁本质就是对资源展开预订!

            2.2 整体使用资源!!

    3. 如果申请锁的时候,锁被别人已经拿走了,怎么办?

            其他线程要进行阻塞等待

    4. 线程在访问临界区代码的时候,可以不可以切换?可以切换!!

            4.1 我被切走的时候,别人能进来吗?不能!因为我是抱着锁,被切换的!临界区的代码就是被串行的!这也是加锁效率低的原因!也体现了原子性(要么不做,要么做完)!

    锁是如何实现的

    现在大家已经意识到单纯的 i++ 或者 ++i 都不是原子的,有可能会有数据一致性问题。
    在内核中,为了实现互斥锁操作,大多数体系结构都提供了swap或exchange指令,该指令的作用是把寄存器和内存单元的数据相交换,由于只有一条指令,保证了原子性,即使是多处理器平台,访问内存的 总线周期也有先后,一个处理器上的交换指令执行时,另一个处理器的交换指令只能等待总线周期。 

    将%al看成一个寄存器,把 0 movb到 %al中,xchgb将内存中的变量与寄存器中的做了直接的交换,不需要中间变量。(我们假定mutex一开始的数据是:1表示锁没有被申请;0表示锁被申请了)。线程执行判断,如果%al中的内容>0,则申请锁成功然后返回,否则挂起等待,等待完成被唤醒,goto lock重新申请锁。

    1. CPU的寄存器只有一套,被所有的线程共享。但是寄存器中的数据,属于执行流上下文,属于执行流私有的数据!
    2. CUP在执行代码的时候,一定要有对应的执行载体 -- 线程&&进程。
    3. 数据在内存中,是被所有线程所共享的

    结论:把数据从内存移动到寄存器,本质是把数据从共享,变成线程私有!


    重新理解加锁

    当线程A执行第一行代码时,此时%al寄存器中为0,内存mutex中为1(图1);执行第二条代码时内存中mutex中的数据与%al进行交换,变为%al中值为1,mutex的值为0(图2);我们假设线程A执行第三行代码的时候被切换走,线程A会保存自身的上下文,带走%al中的数据,此时线程A处在第三行。

            这时线程B来了,并且开始走第一行和第二行代码,由于内存中mutex的值为0(还是处于图2的状态),交换之后%al的值还是0。所以当线程B执行到第3行代码的时候只能跳到第6行,进行挂起等待。

            线程B被挂起,线程A被重新切回,并恢复上文数据,从第三行开始执行,进入if,调用接口pthread_mutex_lock,return 0表示加锁成功,进入临界区。所以此时线程A被称为:申请锁成功。在上面代码中,加锁就是执行第二行代码:xchgb,只有一条汇编代码,交换不是拷贝,只有一个“1”,持有1的,就表示持有锁!

            当线程A执行完临界区的代码后,进行解锁,执行第八行代码,将自身持有的“1”movb到内存中(这样就回到了图1的状态),接着唤醒正在等待mutex的线程B,线程B被唤醒后,执行第七行代码,继续goto lock重新申请锁。

    http://www.yayakq.cn/news/554341/

    相关文章:

  • 常州做网站基本流程做英德红茶的网站
  • 如何制作橡皮泥 简单seo优化教程自学网
  • 免费发布信息网站小程序代码生成器
  • 龙岗营销网站建设公司做食品研发都有哪些网站
  • 免备案域名购买网站戴尔网站建设
  • 学校网站开发招标wordpress开启raid
  • 动力网站产品展示网站模板源码
  • 网站打开速度游戏网络游戏
  • 厦门市翔安建设局网站怎么在自己电脑上建设网站
  • 网上书店网站开发代码深圳设计网站费用
  • 计算机做网站2018建设网站
  • 如何自建网站 卖东西百度流量推广
  • 网页设计欣赏网站外贸网站有哪些
  • 讯美 深圳网站建设如何制作简易网站
  • js制作简单的公司首页长沙企业网站seo
  • 网站建设总体规划包括哪些方面网片焊接
  • 网站建设 推广薪资做境外的网站网站违法么
  • 惠州网站关键字优化深圳网站建设 猴王网络
  • 电子商务网站建设期末试题及答案网站模版上线需要什么
  • 七米网站建设推广优化优书网有官方app吗
  • 网站公司策划书开发流程和步骤
  • 亚马逊怎么做网站推广物联网应用技术学什么
  • 中小企业网站积木式搭建零食网站模板
  • 百度云服务器挂网站网站开发商业秘密保密协议
  • 上海网站建设培训微信广告推广如何收费
  • 手表网站的结构90设计首页官网详情页
  • 广告设计接单网站普通人开网店赚钱吗
  • 注册一个自己的网站怎么进行网站建设
  • 江阴网站建设哪家好南通市建设工程网站
  • 旅游投资公司网站建设塘沽生活网