成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

Swoole 源碼分析——內(nèi)存模塊之共享內(nèi)存

diabloneo / 2598人閱讀

摘要:前言我們知道,由于沒有多線程模型,所以更多的使用多進(jìn)程模型,因此代碼相對來說更加簡潔,減少了各種線程鎖的阻塞與同步,但是也帶來了新的問題數(shù)據(jù)同步。相比多線程之前可以直接共享進(jìn)程的內(nèi)存,進(jìn)程之間數(shù)據(jù)的相互同步依賴于共享內(nèi)存。

前言

我們知道,由于 PHP 沒有多線程模型,所以 swoole 更多的使用多進(jìn)程模型,因此代碼相對來說更加簡潔,減少了各種線程鎖的阻塞與同步,但是也帶來了新的問題:數(shù)據(jù)同步。相比多線程之前可以直接共享進(jìn)程的內(nèi)存,進(jìn)程之間數(shù)據(jù)的相互同步依賴于共享內(nèi)存。本文將會講解 swoole 中共享內(nèi)存的源碼。

前置知識:

mmap 函數(shù)的使用: APUE 學(xué)習(xí)筆記——高級 IO

共享內(nèi)存: APUE 學(xué)習(xí)筆記——進(jìn)程間通信

共享內(nèi)存數(shù)據(jù)結(jié)構(gòu)
typedef struct _swShareMemory_mmap
{
    size_t size;
    char mapfile[SW_SHM_MMAP_FILE_LEN];
    int tmpfd;
    int key;
    int shmid;
    void *mem;
} swShareMemory;

注意 mem 是一個 void 類型的指針,用于存放共享內(nèi)存的首地址。這個成員變量相當(dāng)于面向?qū)ο笾械?this 指針,通過它就可以訪問到 swShareMemory 的各個成員。

size 代表共享內(nèi)存的大小(不包括 swShareMemory 結(jié)構(gòu)體大小), mapfile[] 代表共享內(nèi)存使用的內(nèi)存映射文件的文件名, tmpfd 為內(nèi)存映射文件的描述符。key 代表使用 System Vshm 系列函數(shù)創(chuàng)建的共享內(nèi)存的 key 值, shmidshm 系列函數(shù)創(chuàng)建的共享內(nèi)存的 id(類似于fd),這兩個由于不是 POSIX 標(biāo)準(zhǔn)定義的 api,用途有限。

共享內(nèi)存的申請與創(chuàng)建

swoole 在申請共享內(nèi)存時常常調(diào)用的函數(shù)是 sw_shm_malloc,這個函數(shù)可以為進(jìn)程匿名申請一大塊連續(xù)的共享內(nèi)存:

void* sw_shm_malloc(size_t size)
{
    swShareMemory object;
    void *mem;
    size += sizeof(swShareMemory);
    mem = swShareMemory_mmap_create(&object, size, NULL);
    if (mem == NULL)
    {
        return NULL;
    }
    else
    {
        memcpy(mem, &object, sizeof(swShareMemory));
        return mem + sizeof(swShareMemory);
    }
}

sw_shm_malloc 函數(shù)可以看出,雖然我們申請的是 size,但是實際申請的內(nèi)存是要略大的,因為還要加上 swShareMemory 這個結(jié)構(gòu)體。當(dāng)函數(shù)返回時,也不會直接返回申請的內(nèi)存首地址,而是復(fù)制了 object 各個成員變量的值后,在申請的首地址上加上 swShareMemory 的大小。

void *swShareMemory_mmap_create(swShareMemory *object, size_t size, char *mapfile)
{
    void *mem;
    int tmpfd = -1;
    int flag = MAP_SHARED;
    bzero(object, sizeof(swShareMemory));

#ifdef MAP_ANONYMOUS
    flag |= MAP_ANONYMOUS;
#else
    if (mapfile == NULL)
    {
        mapfile = "/dev/zero";
    }
    if ((tmpfd = open(mapfile, O_RDWR)) < 0)
    {
        return NULL;
    }
    strncpy(object->mapfile, mapfile, SW_SHM_MMAP_FILE_LEN);
    object->tmpfd = tmpfd;
#endif

#if defined(SW_USE_HUGEPAGE) && defined(MAP_HUGETLB)
    if (size > 2 * 1024 * 1024)
    {
        flag |= MAP_HUGETLB;
    }
#endif

    mem = mmap(NULL, size, PROT_READ | PROT_WRITE, flag, tmpfd, 0);
#ifdef MAP_FAILED
    if (mem == MAP_FAILED)
#else
    if (!mem)
#endif
    {
        swWarn("mmap(%ld) failed. Error: %s[%d]", size, strerror(errno), errno);
        return NULL;
    }
    else
    {
        object->size = size;
        object->mem = mem;
        return mem;
    }
}

由于 swoole 的各個進(jìn)程都是由 master 進(jìn)程所建立,也就是各個進(jìn)程之間存在親戚關(guān)系, 因此swShareMemory_mmap_create 函數(shù)直接以 匿名映射 、(/dev/zero 設(shè)備) 的方式利用 mmap 建立共享內(nèi)存,并沒有 open 具體的共享內(nèi)存文件,或者調(diào)用 shm_open 打開 POSIX IPC 名字。

值得注意的是 MAP_HUGETLB,這個是 linux 內(nèi)核 2.6.32 引入的一個 flags,用于使用大頁面分配共享內(nèi)存。大頁是相對傳統(tǒng) 4K 小頁而言的,一般來說常見的體系架構(gòu)都會提供2種大頁大小,比如常見的 2M 大頁和 1G 大頁。使用大頁可以減少頁表項數(shù)量,從而減少 TLB Miss 的概率,提升系統(tǒng)訪存性能。當(dāng)然有利必有弊,使用大頁降低了內(nèi)存管理的粒度和靈活性,如果程序并不是對內(nèi)存的使用量特別大,使用大頁還可能造成內(nèi)存的浪費(fèi)。

共享內(nèi)存的 calloc

callocmalloc 大同小異,無非多了一個 num 參數(shù)

void* sw_shm_calloc(size_t num, size_t _size)
{
    swShareMemory object;
    void *mem;
    void *ret_mem;
    int size = sizeof(swShareMemory) + (num * _size);
    mem = swShareMemory_mmap_create(&object, size, NULL);
    if (mem == NULL)
    {
        return NULL;
    }
    else
    {
        memcpy(mem, &object, sizeof(swShareMemory));
        ret_mem = mem + sizeof(swShareMemory);
        bzero(ret_mem, size - sizeof(swShareMemory));
        return ret_mem;
    }
}
共享內(nèi)存的 realloc

realloc 函數(shù)用于修改已申請的內(nèi)存大小,邏輯非常簡單,先申請新的內(nèi)存,進(jìn)行復(fù)制后,再釋放舊的內(nèi)存:

void* sw_shm_realloc(void *ptr, size_t new_size)
{
    swShareMemory *object = ptr - sizeof(swShareMemory);
    void *new_ptr;
    new_ptr = sw_shm_malloc(new_size);
    if (new_ptr == NULL)
    {
        return NULL;
    }
    else
    {
        memcpy(new_ptr, ptr, object->size);
        sw_shm_free(ptr);
        return new_ptr;
    }
}
修改共享內(nèi)存的權(quán)限

在內(nèi)存映射完成后,由標(biāo)記讀、寫、執(zhí)行權(quán)限的 PROT_READ、PROT_WRITEPROT_EXEC 等權(quán)限仍可以被 mprotect 系統(tǒng)調(diào)用所修改。

int sw_shm_protect(void *addr, int flags)
{
    swShareMemory *object = (swShareMemory *) (addr - sizeof(swShareMemory));
    return mprotect(object, object->size, flags);
}
共享內(nèi)存的釋放
void sw_shm_free(void *ptr)
{
    swShareMemory *object = ptr - sizeof(swShareMemory);
    swShareMemory_mmap_free(object);
}

int swShareMemory_mmap_free(swShareMemory *object)
{
    return munmap(object->mem, object->size);
}

文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/29198.html

相關(guān)文章

  • Swoole 源碼分析——基礎(chǔ)模塊 Channel 隊列

    摘要:前言內(nèi)存數(shù)據(jù)結(jié)構(gòu),類似于的通道,底層基于共享內(nèi)存互斥鎖實現(xiàn),可實現(xiàn)用戶態(tài)的高性能內(nèi)存隊列。是當(dāng)前隊列占用的內(nèi)存大小,用來指定是否使用共享內(nèi)存是否使用鎖是否使用通知。 前言 內(nèi)存數(shù)據(jù)結(jié)構(gòu) Channel,類似于 Go 的 chan 通道,底層基于 共享內(nèi)存 + Mutex 互斥鎖實現(xiàn),可實現(xiàn)用戶態(tài)的高性能內(nèi)存隊列。Channel 可用于多進(jìn)程環(huán)境下,底層在讀取寫入時會自動加鎖,應(yīng)用層不需...

    txgcwm 評論0 收藏0
  • Swoole 源碼分析——內(nèi)存模塊共享內(nèi)存swoole_table

    摘要:如果互斥鎖的持有者死亡了,或者持有這樣的互斥鎖的進(jìn)程了互斥鎖所在的共享內(nèi)存或者持有這樣的互斥鎖的進(jìn)程執(zhí)行了調(diào)用,則會解除鎖定該互斥鎖?;コ怄i的下一個持有者將獲取該互斥鎖并返回錯誤。 前言 swoole_table 一個基于共享內(nèi)存和鎖實現(xiàn)的超高性能,并發(fā)數(shù)據(jù)結(jié)構(gòu)。用于解決多進(jìn)程/多線程數(shù)據(jù)共享和同步加鎖問題。 swoole_table 的數(shù)據(jù)結(jié)構(gòu) swoole_table 實際上...

    Invoker 評論0 收藏0
  • Swoole 源碼分析——內(nèi)存模塊內(nèi)存

    摘要:前言中為了更好的進(jìn)行內(nèi)存管理,減少頻繁分配釋放內(nèi)存空間造成的損耗和內(nèi)存碎片,程序設(shè)計并實現(xiàn)了三種不同功能的內(nèi)存池,和。比較特殊的是單鏈表內(nèi)存池的內(nèi)存只能增加不會減少。 前言 Swoole 中為了更好的進(jìn)行內(nèi)存管理,減少頻繁分配釋放內(nèi)存空間造成的損耗和內(nèi)存碎片,程序設(shè)計并實現(xiàn)了三種不同功能的內(nèi)存池:FixedPool,RingBuffer 和 MemoryGlobal。 其中 Memor...

    stormzhang 評論0 收藏0
  • Swoole 源碼分析——內(nèi)存模塊swBuffer

    摘要:的數(shù)據(jù)結(jié)構(gòu)數(shù)據(jù)結(jié)構(gòu)中是鏈表元素的個數(shù),是緩沖區(qū)創(chuàng)建時,鏈表元素約定的大小實際大小不一定是這個值,是實際上緩沖區(qū)占用的內(nèi)存總大小。中的有三種,分別應(yīng)用于緩存數(shù)據(jù)發(fā)送文件提醒連接關(guān)閉三種情景。指的是元素的內(nèi)存大小。 前言 swoole 中數(shù)據(jù)的接受與發(fā)送(例如 reactor 線程接受客戶端消息、發(fā)送給客戶端的消息、接受到的來自 worker 的消息、要發(fā)送給 worker 的消息等等)都...

    fyber 評論0 收藏0
  • Swoole 源碼分析——Server模塊初始化

    摘要:如果在調(diào)用之前我們設(shè)置了,但是不在第二個進(jìn)程啟動前這個套接字,那么第二個進(jìn)程仍然會在調(diào)用函數(shù)的時候出錯。 前言 本節(jié)主要介紹 server 模塊進(jìn)行初始化的代碼,關(guān)于初始化過程中,各個屬性的意義,可以參考官方文檔: SERVER 配置選項 關(guān)于初始化過程中,用于監(jiān)聽的 socket 綁定問題,可以參考: UNP 學(xué)習(xí)筆記——基本 TCP 套接字編程 UNP 學(xué)習(xí)筆記——套接字選項 構(gòu)造...

    Half 評論0 收藏0

發(fā)表評論

0條評論

最新活動
閱讀需要支付1元查看
<