主頁 > 軟體設計 > Linux_多執行緒與鎖

Linux_多執行緒與鎖

2021-05-02 19:01:33 軟體設計

文章目錄

  • 1 .常見鎖的概念
    • 1.1 死鎖
    • 1.2 死鎖四個必要條件
    • 1.3 避免死鎖
  • 2. Linux執行緒同步
    • 2.1 條件變數
    • 2.2 同步概念與競態條件
    • 2.3 編碼實作方式
    • 2.4 相關介面函式
      • 2.4.1 初始化條件變數
      • 2.4.2 銷毀條件變數
      • 2.4.3 等待條件滿足
      • 2.4.4 喚醒等待
    • 2.5 代碼示例
  • 3. 生產者消費者模型
    • 3.1 圖示詳解
    • 3.2 代碼示例
  • 4. POSIX 信號量
    • 4.1 POSIX概念
    • 4.2 POSIX函式
      • 4.2.1 初始化信號量
      • 4.2.2 銷毀信號量
      • 4.2.3 等待信號量
      • 4.2.4 發布信號量
    • 4.3 基于環形佇列的生產消費模型
    • 4.3 代碼示例

  • 在前面的博客【Linux_深究多執行緒—>link】中已經講了有關多執行緒操作的有關操作和鎖的基本概念,這章將接著上一章的內容對執行緒與鎖的有關概念和操作繼續深究,

1 .常見鎖的概念

1.1 死鎖

  • 死鎖是指在一組行程中的各個行程均占有不會釋放的資源,但因互相申請被其他行程所站用不會釋放的資源而處于的一種永久等待狀態,

1.2 死鎖四個必要條件

  1. 互斥條件:一個資源每次只能被一個執行流使用
  2. 請求與保持條件:一個執行流因請求資源而阻塞時,對已獲得的資源保持不放
  3. 不剝奪條件:一個執行流已獲得的資源,在末使用完之前,不能強行剝奪
  4. 回圈等待條件:若干執行流之間形成一種頭尾相接的回圈等待資源的關系

注意:要形成死鎖,四個條件缺一不可,所以解決死鎖的方法就是破壞四個必要條件中的一個以上,常見有銀行家演算法/死鎖檢測演算法等,

1.3 避免死鎖

  1. 破壞死鎖的四個必要條件
  2. 加鎖順序一致
  3. 避免鎖未釋放的場景
  4. 資源一次性分配

問題

  • 一個執行緒一把鎖有沒有可能形成死鎖呢
  • 答:有,下面代碼演示:
  • 在這里插入圖片描述
  • 原因是同一把鎖被申請兩次,且該鎖還沒有被解鎖,還被占著,自己和自己杠上,即出現死鎖,

2. Linux執行緒同步

2.1 條件變數

  • 當一個執行緒互斥地訪問某個變數時,它可能發現在其它執行緒改變狀態之前,它什么也做不了,
  • 同步存在是為了多執行緒協同高效完成某些事情
  • 例如一個執行緒訪問佇列時,發現佇列為空,它只能等待,只到其它執行緒將一個節點添加到佇列中,這種情況就需要用到條件變數,

2.2 同步概念與競態條件

  • 同步:在保證資料安全的前提下,讓執行緒能夠按照某種特定的順序訪問臨界資源,從而有效避免饑餓問題,叫做同步,
  • 競態條件:因為時序問題,而導致程式例外,我們稱之為競態條件,在執行緒場景下,這種問題也不難理解,

2.3 編碼實作方式

  1. 如果條件不滿足,等待,釋放鎖,
  2. 通知機制,

2.4 相關介面函式

2.4.1 初始化條件變數

int pthread_cond_init(pthread_cond_t *restrict cond,const pthread_condattr_t *restrict attr);

引數

  • cond:要初始化的條件變數
  • attr:NULL

2.4.2 銷毀條件變數

int pthread_cond_destroy(pthread_cond_t *cond)

2.4.3 等待條件滿足

int pthread_cond_wait(pthread_cond_t *restrict cond,pthread_mutex_t *restrict mutex);

引數

  • cond:要在這個條件變數上等待
  • mutex:互斥量,

2.4.4 喚醒等待

int pthread_cond_broadcast(pthread_cond_t *cond);
int pthread_cond_signal(pthread_cond_t *cond);

2.5 代碼示例

#include<stdio.h>
#include<unistd.h>
#include<pthread.h>
pthread_mutex_t lock;//創建鎖
pthread_cond_t cond;//創建環境變數

void *run1(void *arg)//負責等待執行緒二發來信號開始執行
{
  const char *name=(char*)arg;
  while(1)
  {
    pthread_cond_wait(&cond,&lock);//等待
    printf("%s get singal\n",name);
  }
}
void *run2(void *arg)//負責給執行緒一發送信號
{
  const char *name=(char*)arg;
  while(1)
  {
    sleep(2);
    pthread_cond_signal(&cond);//喚醒等待
    printf("%s signal done!\n",name);
  }
}
int main()
{
  pthread_mutex_init(&lock,NULL);//初始化鎖
  pthread_cond_init(&cond,NULL);//初始化環境變數
  pthread_t t1;
  pthread_t t2;

  pthread_create(&t1,NULL,run1,"thread1");//創造兩個新執行緒
  pthread_create(&t2,NULL,run2,"thread2");

  pthread_join(t1,NULL);//等待兩個執行緒退出
  pthread_join(t2,NULL);
  
  pthread_mutex_destroy(&lock);//銷毀鎖
  pthread_cond_destroy(&cond);//銷毀環境變數

  return 0;
}

運行結果
在這里插入圖片描述
問題

  • 為什么pthread_cond_wait()需要互斥量呢
  • 答:
  1. 條件等待是執行緒間同步的一種手段,如果只有一個執行緒,條件不滿足,一直等下去都不會滿足所以必須要有一個執行緒通過某些操作,改變共享變數,使原先不滿足的條件變得滿足,并且友好的通知等待在條件變數上的執行緒,
  2. 條件不會無緣無故的突然變得滿足了,必然會牽扯到共享資料的變化,所以一定要用互斥鎖來保護,沒有互斥鎖就無法安全的獲取和修改共享資料,
  3. 簡單來說,pthread_cond_wait()中還要帶上鎖是因為,如果該執行緒在等待時,此時應該將臨界區進行解鎖,讓另外的執行緒在該執行緒等待時,可以進入到臨界區,要不然它在等待時還一直加鎖狀態,就沒意義,當別的行程給該行程發信號,喚醒它,這個時候從新加鎖,訪問臨界區,保證其原子性,

3. 生產者消費者模型

問題

  • 為何要使用生產者消費者模型 ?
  • 生產者消費者模式就是通過一個容器來解決生產者和消費者的強耦合問題,生產者和消費者彼此之間不直接通訊,而通過阻塞佇列來進行通訊,所以生產者生產完資料之后不用等待消費者處理,直接扔給阻塞佇列,消費者不找生產者要資料,而是直接從阻塞佇列里取,阻塞佇列就相當于一個緩沖區,平衡了生產者和消費者的處理能力,這個阻塞佇列就是用來給生產者和消費者解耦的,

生產者消費者模型優點

  • 解耦
  • 支持并發
  • 支持忙閑不均

3.1 圖示詳解

在這里插入圖片描述

  • 基于BlockingQueue的生產者消費者模型 ,BlockingQueue 在多執行緒編程中阻塞佇列(Blocking Queue)是一種常用于實作生產者和消費者模型的資料結構,
  • 其與普通的佇列區別在于,當佇列為空時,從佇列獲取元素的操作將會被阻塞,直到佇列中被放入了元素;當佇列滿時,往佇列里存放元素的操作也會被阻塞,直到有元素被從佇列中取出(以上的操作都是基于不同的執行緒來說的,執行緒在對阻塞佇列行程操作時會被阻塞),
  • 生產者消費者“321”
  • 3->3種關系:生產者&消費者(互斥/同步),生產者&生產者(互斥),消費者&消費者(互斥)
  • 2->2種角色:生產者,消費者
  • 3->一個交易場所

3.2 代碼示例

ps.h

#ifndef __QUEUE_BLOCK_H__
#define __QUEUE_BLOCK_H__
#include<unistd.h>
#include<iostream>
#include<pthread.h>
#include<queue>
using namespace std;
class Task
{
public:
  int x;
  int y;
public:
  Task(int _x,int _y):x(_x),y(_y)
  {}
  Task()
  {}
  int Run()
  {
    return x+y;
  }
  ~Task()
  {}
};
class BlockQueue
{
private:
  queue<Task> q;
  size_t cap;
  pthread_mutex_t lock;
  pthread_cond_t c_cond;
  pthread_cond_t p_cond;
public:
  //判滿
  bool IsFull()
  {
    return q.size()>=cap;
  }
  //判空
  bool IsEmpty()
  {
    return q.empty();
  }
  //解鎖
  void UnlockQueue()
  {
    pthread_mutex_unlock(&lock);
  }
  //喚醒消費者
  void WakeUpConsumer()
  {
    cout<<"WakeUpConsumer"<<endl;
    pthread_cond_signal(&c_cond);
  }
  //喚醒生產者
  void WakeUpProductor()
  {
    cout<<"WakeUpProductor"<<endl;
    pthread_cond_signal(&p_cond);
  }
  //pthread_cond_wait傳入lock引數:
  //在條件滿足時,消費者or生產者持有鎖進入臨界區執行,當判斷條件不滿足時,呼叫對應的wait函式
  //在消費者or生產者等待時,呼叫對應的Wait函式,自動釋放lock
  //消費者等待,必須解鎖,讓另一個角色持有鎖,以保證執行緒之間友好,在
  void ConsumerWait()
  {
    cout<<"ConsumerWait"<<endl;
    pthread_cond_wait(&c_cond,&lock);
  }
  //生產者等待
  void ProductWait()
  {
    cout<<"ProductWait"<<endl;
    pthread_cond_wait(&p_cond,&lock);
  }
public:
    BlockQueue(int _cap):cap(_cap)
    {
      pthread_mutex_init(&lock,nullptr);
      pthread_cond_init(&c_cond,nullptr);
      pthread_cond_init(&p_cond,nullptr);
    }
    ~BlockQueue()
    {
      pthread_mutex_destroy(&lock);
      pthread_cond_destroy(&p_cond);
      pthread_cond_destroy(&c_cond);
    }
    //消費者消費,拿取or執行佇列中的資料以及任務并執行
    void Put(Task in)
    {
      UnlockQueue();
      if(IsFull())
      {
        WakeUpConsumer();
        ProductWait();
      }
      q.push(in);
      UnlockQueue();
    }
    //生產者生產,向佇列中塞資料或者任務
    void Get(Task &out)
    {
      UnlockQueue();
      if(IsEmpty())
      {
        WakeUpProductor();
        ConsumerWait();
      }
      out=q.front();
      q.pop();
      UnlockQueue();
    }
};
#endif

ps.cpp

#include "block.h"
using namespace std;

void *consumer_run(void *arg)
{
  //int num=(int)arg;
  pthread_mutex_t lock;
  BlockQueue *bq=(BlockQueue*)arg;
  while(true)                         
  {                            
    pthread_mutex_lock(&lock);
    //int data;
    Task t;
    bq->Get(t); 
    //t.Run();
    pthread_mutex_unlock(&lock);
    cout<<"consumer"<<t.x<<"+"<<t.y<<"="<<t.Run()<<endl;
    sleep(1); 
  }
  //pthread_mutex_unlock(&lock);
}
void *productor_run(void *arg)
{
  //int num=(int)arg;
  pthread_mutex_t lock;
  sleep(1);
  BlockQueue *bq=(BlockQueue*)arg;
  //int count=0;
  while(true)
  {
    int x=rand()%10+1;
    int y=rand()%100+1;
    pthread_mutex_lock(&lock);
    Task t(x,y);
    bq->Put(t);
    pthread_mutex_unlock(&lock);
    cout<<"productor "<<x<<"+"<<y<<"=?"<<endl;
  }
  //pthread_mutex_unlock(&lock);
}

int main()
{
  BlockQueue *bq = new BlockQueue(5);
  pthread_t con1,pro1;
  pthread_create(&con1,nullptr,consumer_run,(void*)bq);
  pthread_create(&pro1,nullptr,productor_run,(void*)bq);
  //pthread_create(&con2,nullptr,consumer_run,(void*)bq);
  //pthread_create(&pro2,nullptr,productor_run,(void*)bq);
  pthread_join(con1,nullptr);
  //pthread_join(con2,nullptr);
  pthread_join(pro1,nullptr);
  //pthread_join(pro2,nullptr);
  return 0;
}

運行結果
在這里插入圖片描述

4. POSIX 信號量

4.1 POSIX概念

  • POSIX信號量和SystemV信號量作用相同,都是用于同步操作,達到無沖突的訪問共享資源目的, 但POSIX可以用于執行緒間同步,
    在這里插入圖片描述

4.2 POSIX函式

4.2.1 初始化信號量

#include <semaphore.h>
int sem_init(sem_t *sem, int pshared, unsigned int value)

引數

  • pshared:0表示執行緒間共享,非零表示行程間共享
  • value:信號量初始值

4.2.2 銷毀信號量

int sem_destroy(sem_t *sem)

4.2.3 等待信號量

int sem_wait(sem_t *sem);

功能

  • 等待信號量,會將信號量的值減1 //P()

4.2.4 發布信號量

int sem_post(sem_t *sem)//V()

功能

  • 發布信號量,表示資源使用完畢,可以歸還資源了,將信號量值加1

上面生產者-消費者的例子是基于queue的,其空間可以動態分配,現在基于固定大小的環形佇列重寫這個程式(POSIX信號量):

4.3 基于環形佇列的生產消費模型

  • 環形佇列采用陣列模擬,用模運算來模擬環狀特性
  • 環形結構起始狀態和結束狀態都是一樣的,不好判斷為慷訓者為滿,所以可以通過加計數器或者標記位來判斷滿或者空,另外也可以預留一個空的位置,作為滿的狀態
  • 但是我們現在有信號量這個計數器,就很簡單的進行多執行緒間的同步程序

在這里插入圖片描述

4.3 代碼示例

// RingQueue.hpp

#pragma once
#include <iostream>
#include <pthread.h>
#include <semaphore.h>
#include <unistd.h>
#include <vector>

class RingQueue
{
  private:
    std::vector<int> _q;
    int _cap;
    //信號量
    sem_t sem_blank;
    sem_t sem_data;
  //資源下標
    int pro_sub;
    int con_sub;

  private:
    void P(sem_t &sem)
    {
      sem_wait(&sem);
    }

    void V(sem_t &sem)
    {
      sem_post(&sem);
    }


  public:
  RingQueue(int cap=6)
    :_cap(cap)
     ,_q(cap)
  {
    sem_init(&sem_blank,0,_cap);//格子個數一開始為容量大小
    sem_init(&sem_data,0,0);//資料一開始為0
    pro_sub=0;
    con_sub=0;
  }
  
  void Put(const int &data)
  {
    P(sem_blank);//申請格子資源,判斷是否還有容量,格子--
    _q[pro_sub]=data;
    pro_sub++;
    pro_sub%=_cap;//越界回環
    V(sem_data);//資料++
  }

  void Get(int &data)
  {
    P(sem_data);//申請資料資源,判斷是否還有資料,資料--
    data=_q[con_sub];
    con_sub++;
    con_sub%=_cap;
    V(sem_blank);//消耗資料,格子++
  }

  ~RingQueue()
  {
    sem_destroy(&sem_blank);
    sem_destroy(&sem_data);
    pro_sub=con_sub=0;
  }

};

//main.cpp

#include "RingQueue.hpp"

pthread_mutex_t pro_lock;//生產者組內競爭鎖
pthread_mutex_t con_lock;//消費者組內競爭鎖

int count=0;//生產者資料

void Lock(pthread_mutex_t &lock)
{
  pthread_mutex_lock(&lock);
}

void ULock(pthread_mutex_t &lock)
{
  pthread_mutex_unlock(&lock);
}

  void *Get(void *arg)
{
  RingQueue *q=(RingQueue*)arg;
  while(1)
  {
    usleep(1);
    int data=0;
    Lock(con_lock);//組內競爭
    q->Get(data);//獲取資料
    ULock(con_lock);
    std::cout<<"consumer get data...:"<<data<<std::endl;
  }
}
void *Put(void *arg)
{
  RingQueue *q=(RingQueue*)arg;
  while(1)
  {
    sleep(1);//增加系統呼叫
    Lock(pro_lock);//組內競爭
    int number = (++count)%10l;
    q->Put(number);
    ULock(pro_lock);
    std::cout<<"productor put data...."<< number << std::endl;
  }

}

int main()
{
//創建交易場所
  RingQueue *q=new RingQueue(5);

  //初始化鎖
  pthread_mutex_init(&con_lock,nullptr);
  pthread_mutex_init(&pro_lock,nullptr);
  
  //創建執行緒
  pthread_t tid1,tid2,tid3,tid4,tid5,tid6;
  pthread_create(&tid1,nullptr,Put,q);
  pthread_create(&tid2,nullptr,Put,q);
  pthread_create(&tid3,nullptr,Put,q);
  pthread_create(&tid4,nullptr,Get,q);
  pthread_create(&tid5,nullptr,Get,q);
  pthread_create(&tid6,nullptr,Get,q);


//等待執行緒、避免記憶體泄漏,不關心回傳值
  pthread_join(tid1,nullptr);
  pthread_join(tid2,nullptr);
  pthread_join(tid3,nullptr);
  pthread_join(tid4,nullptr);
  pthread_join(tid5,nullptr);
  pthread_join(tid6,nullptr);

  //銷毀作業
  pthread_mutex_destroy(&con_lock);
  pthread_mutex_destroy(&pro_lock);
  delete q;
  
  return 0;
}

運行結果
在這里插入圖片描述

轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/282144.html

標籤:其他

上一篇:第十二屆藍橋杯C++賽后感

下一篇:Qt開發技術:Qt拽拖開發(一)拽托框架詳解及Demo

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • 面試突擊第一季,第二季,第三季

    第一季必考 https://www.bilibili.com/video/BV1FE411y79Y?from=search&seid=15921726601957489746 第二季分布式 https://www.bilibili.com/video/BV13f4y127ee/?spm_id_fro ......

    uj5u.com 2020-09-10 05:35:24 more
  • 第三單元作業總結

    1.前言 這應該是本學期最后一次寫作業總結了吧。總體來說,對作業的節奏也差不多掌握了,作業做起來的效率也更高了。雖然和之前的作業一樣,作業中都要用到新的知識,但是相比之前,更加懂得了如何利用工具以及資料。雖然之間卡過殼,但總體而言,這幾次作業還算完成的比較好。 2.作業程序總結 相比前兩個單元,此單 ......

    uj5u.com 2020-09-10 05:35:41 more
  • 北航OO(2020)第四單元博客作業暨課程總結博客

    北航OO(2020)第四單元博客作業暨課程總結博客 本單元作業的架構設計 在本單元中,由于UML圖具有比較清晰的樹形結構,因此我對其中需要進行查詢操作的元素進行了包裝,在樹的父節點中存盤所有孩子的參考。考慮到性能問題,我采用了快取機制,一次查詢后盡可能快取已經遍歷過的資訊,以減少遍歷次數。 本單元我 ......

    uj5u.com 2020-09-10 05:35:48 more
  • BUAA_OO_第四單元

    一、UML決議器設計 ? 先看下題目:第四單元實作一個基于JDK 8帶有效性檢查的UML(Unified Modeling Language)類圖,順序圖,狀態圖分析器 MyUmlInteraction,實際上我們要建立一個有向圖模型,UML中的物件(元素)可能與同級元素連接,也可與低級元素相連形成 ......

    uj5u.com 2020-09-10 05:35:54 more
  • 6.1邏輯運算子

    邏輯運算子 1. && 短路與 運算式1 && 運算式2 01.運算式1為true并且運算式2也為true 整體回傳為true 02.運算式1為false,將不會執行運算式2 整體回傳為false 03.只要有一個運算式為false 整體回傳為false 2. || 短路或 運算式1 || 運算式2 ......

    uj5u.com 2020-09-10 05:35:56 more
  • BUAAOO 第四單元 & 課程總結

    1. 第四單元:StarUml檔案決議 本單元采用了圖模型決議UML。 UML檔案可以抽象為圖、子圖、邊的邏輯結構。 在實作中,圖的節點包括類、介面、屬性,子圖包括狀態圖、順序圖等。 采用了三次遍歷UML元素的方法建圖,第一遍遍歷建點,第二、三次遍歷設定屬性、連邊,實作圖物件的初始化。這里借鑒了一些 ......

    uj5u.com 2020-09-10 05:36:06 more
  • 談談我對C# 多型的理解

    面向物件三要素:封裝、繼承、多型。 封裝和繼承,這兩個比較好理解,但要理解多型的話,可就稍微有點難度了。今天,我們就來講講多型的理解。 我們應該經常會看到面試題目:請談談對多型的理解。 其實呢,多型非常簡單,就一句話:呼叫同一種方法產生了不同的結果。 具體實作方式有三種。 一、多載 多載很簡單。 p ......

    uj5u.com 2020-09-10 05:36:09 more
  • Python 資料驅動工具:DDT

    背景 python 的unittest 沒有自帶資料驅動功能。 所以如果使用unittest,同時又想使用資料驅動,那么就可以使用DDT來完成。 DDT是 “Data-Driven Tests”的縮寫。 資料:http://ddt.readthedocs.io/en/latest/ 使用方法 dd. ......

    uj5u.com 2020-09-10 05:36:13 more
  • Python里面的xlrd模塊詳解

    那我就一下面積個問題對xlrd模塊進行學習一下: 1.什么是xlrd模塊? 2.為什么使用xlrd模塊? 3.怎樣使用xlrd模塊? 1.什么是xlrd模塊? ?python操作excel主要用到xlrd和xlwt這兩個庫,即xlrd是讀excel,xlwt是寫excel的庫。 今天就先來說一下xl ......

    uj5u.com 2020-09-10 05:36:28 more
  • 當我們創建HashMap時,底層到底做了什么?

    jdk1.7中的底層實作程序(底層基于陣列+鏈表) 在我們new HashMap()時,底層創建了默認長度為16的一維陣列Entry[ ] table。當我們呼叫map.put(key1,value1)方法向HashMap里添加資料的時候: 首先,呼叫key1所在類的hashCode()計算key1 ......

    uj5u.com 2020-09-10 05:36:38 more
最新发布
  • 【中介者設計模式詳解】C/Java/JS/Go/Python/TS不同語言實作

    * 中介者模式是一種行為型設計模式,它可以用來減少類之間的直接依賴關系,
    * 將物件之間的通信封裝到一個中介者物件中,從而使得各個物件之間的關系更加松散。
    * 在中介者模式中,物件之間不再直接相互互動,而是通過中介者來中轉訊息。 ......

    uj5u.com 2023-04-20 08:20:47 more
  • 露天煤礦現場調研和交流案例分享

    他們集團的資訊化公司及研究院在一個礦區正在做智能礦山的統一平臺的 試點,專案投資大概1億,包括了礦山的各方面的內容,顯示得我們這次交流有點多余。他們2年前開始做智能礦山的規劃,有很多煤礦行業專家的加持,他們的描述是非常完美,但是去年底應該上線的平臺,現在還沒有看到影子。他們確實有很多場景需求,但是被... ......

    uj5u.com 2023-04-20 08:20:25 more
  • 《社區人員管理》實戰案例設計&個人案例分享

    設計是一個讓人夢想成真程序,開始編碼、測驗、除錯之前進行需求分析和架構設計,才能保證關鍵方面都做正確 ......

    uj5u.com 2023-04-20 08:20:17 more
  • 軟體架構生態化-多角色交付的探索實踐

    作為一個技術架構師,不僅僅要緊跟行業技術趨勢,還要結合研發團隊現狀及痛點,探索新的交付方案。在日常中,你是否遇到如下問題 “ 業務需求排期長研發是瓶頸;非研發角色感受不到研發技改提效的變化;引入ISV 團隊又擔心質量和安全,培訓周期長“等等,基于此我們探索了一種新的技術體系及交付方案來解決如上問題。 ......

    uj5u.com 2023-04-20 08:20:10 more
  • 【中介者設計模式詳解】C/Java/JS/Go/Python/TS不同語言實作

    * 中介者模式是一種行為型設計模式,它可以用來減少類之間的直接依賴關系,
    * 將物件之間的通信封裝到一個中介者物件中,從而使得各個物件之間的關系更加松散。
    * 在中介者模式中,物件之間不再直接相互互動,而是通過中介者來中轉訊息。 ......

    uj5u.com 2023-04-20 08:19:44 more
  • 露天煤礦現場調研和交流案例分享

    他們集團的資訊化公司及研究院在一個礦區正在做智能礦山的統一平臺的 試點,專案投資大概1億,包括了礦山的各方面的內容,顯示得我們這次交流有點多余。他們2年前開始做智能礦山的規劃,有很多煤礦行業專家的加持,他們的描述是非常完美,但是去年底應該上線的平臺,現在還沒有看到影子。他們確實有很多場景需求,但是被... ......

    uj5u.com 2023-04-20 08:19:07 more
  • 《社區人員管理》實戰案例設計&個人案例分享

    設計是一個讓人夢想成真程序,開始編碼、測驗、除錯之前進行需求分析和架構設計,才能保證關鍵方面都做正確 ......

    uj5u.com 2023-04-20 08:18:57 more
  • 軟體架構生態化-多角色交付的探索實踐

    作為一個技術架構師,不僅僅要緊跟行業技術趨勢,還要結合研發團隊現狀及痛點,探索新的交付方案。在日常中,你是否遇到如下問題 “ 業務需求排期長研發是瓶頸;非研發角色感受不到研發技改提效的變化;引入ISV 團隊又擔心質量和安全,培訓周期長“等等,基于此我們探索了一種新的技術體系及交付方案來解決如上問題。 ......

    uj5u.com 2023-04-20 08:18:49 more
  • 05單件模式

    #經典的單件模式 public class Singleton { private static Singleton uniqueInstance; //一個靜態變數持有Singleton類的唯一實體。 // 其他有用的實體變數寫在這里 //構造器宣告為私有,只有Singleton可以實體化這個類! ......

    uj5u.com 2023-04-19 08:42:51 more
  • 【架構與設計】常見微服務分層架構的區別和落地實踐

    軟體工程的方方面面都遵循一個最基本的道理:沒有銀彈,架構分層模型更是如此,每一種都有各自優缺點,所以請根據不同的業務場景,并遵循簡單、可演進這兩個重要的架構原則選擇合適的架構分層模型即可。 ......

    uj5u.com 2023-04-19 08:42:41 more