返回顶部
首页 > 资讯 > 操作系统 >【Linux从入门到精通】通信 | 共享内存(System V)
  • 782
分享到

【Linux从入门到精通】通信 | 共享内存(System V)

linux运维通信共享内存 2023-10-01 08:10:14 782人浏览 独家记忆
摘要

    本篇文章接着上篇文章通信 | 管道通信(匿名管道 & 命名管道)进行讲解。本篇文章的中点内容是共享内存。 文章目录  一、初识与创建共享内存 1、1 什么是共享内存 1、2 共享内存函数 1、2、1 创建共享内存

 

  本篇文章接着上篇文章通信 | 管道通信(匿名管道 & 命名管道)进行讲解。本篇文章的中点内容是共享内存

文章目录

 一、初识与创建共享内存

1、1 什么是共享内存

1、2 共享内存函数

1、2、1 创建共享内存 shmget

1、2、2 ftok 生成 key

1、2、3 获取共享内存 shmget

1、3 demo 代码

二、对共享内存进行相关操作 

2、1 查看/删除 共享内存资源

2、2 共享内存挂接和访问

2、2、1 共享内存的挂接 shmat()

2、2、2 共享内存的访问

2、3 删除共享内存 shmctl 

三、完整共享内存通信 demo 代码

3、1 Log.hpp 日志

3、2 comm.hpp

3、3 shmClient.cpp

3、4 shmServer.cpp


🙋‍♂️ 作者:@Ggggggtm 🙋‍♂️

👀 专栏:Linux从入门到精通  👀

💥 标题:共享内存 💥

 ❣️ 寄语:与其忙着诉苦,不如低头赶路,奋路前行,终将遇到一番好风景 ❣️

 一、初识与创建共享内存

1、1 什么是共享内存

  我们在之前学管道通信时,是怎么实现通信的呢?匿名管道通信的方式是子进程继承父进程的内核数据结构,使得父子进程能够看到同一块空间命名管道信是让不同进程打开同一份文件。我们发现通信的前提就是让不同的进程看到同一份“资源”。当然,共享内存也不例外。

   每个进程都有自己独立的地址空间,所以它们彼此之间不能直接访问对方的内存。而共享内存则提供了一种特殊的内存区域,允许多个进程可以同时访问和操作同一块内存。具体如下图:

  这里再次解释一下上图。我们创建共享内存的过程:一个进程在内核空间申请一个共享内存对象,让后通过页表建立与物理内存的映射。让后另一个进程通过特殊的方法和算法来找到该共享内存并且与其建立映射。下面我们会对上述过程进行详细解释。 

1、2 共享内存函数

1、2、1 创建共享内存 shmget

  shmget函数用于创建一个新的共享内存段或者获取现有的共享内存段的标识符

函数原型为:

int shmget(key_t key, size_t size, int shmflg);

参数说明:

  • key:用于标识共享内存段的键值。可以使用ftok函数生成
  • size:指定共享内存段的大小,以字节为单位。
  • shmflg:用于指定共享内存段的访问权限和标志位,可以使用IPC_CREAT、IPC_EXCL等宏进行设置。

返回值:

  • 如果成功,返回共享内存段的标识符(即共享内存ID)。
  • 如果失败,返回-1,并设置errno。

  更加详细的如下图:

  我们在这里具体解释一下第三个参数 shmflg。这个参数是可以有多个选择的。底层是利用了位图的思想。主要是IPC_CREAT和IPC_EXCL两个选项。

  IPC_CREAT和IPC_EXCL是在shmget函数中使用的标志位,用于指定共享内存段的访问权限和标志。它们在shmget函数的第三个参数shmflg中使用。

  • IPC_CREAT:该标志用于创建一个新的共享内存段。如果指定的key对应的共享内存段不存在,则创建一个新的共享内存段。如果共享内存段已经存在,则返回该共享内存段的标识符(即共享内存ID)。

  • IPC_EXCL:该标志与IPC_CREAT一起使用,在创建共享内存段时起作用。如果指定的key对应的共享内存段已经存在,则shmget函数会失败,并返回-1,并且置errno为EEXIST(资源已存在)。

   我们接下来再看一下 shmget 的具体使用例子。

int shmid = shmget(key, size, IPC_CREAT | permission_flags);

  上述代码中,IPC_CREAT标志位用于创建共享内存段。如果指定的key对应的共享内存段已经存在,那么shmget函数会返回该共享内存段的标识符;如果共享内存段不存在,则会创建一个新的共享内存段,并返回新创建的共享内存段的标识符。

1、2、2 ftok 生成 key

  在函数shmget中,key值是用于标识或检索共享内存段的关键值。它在创建或访问共享内存时起到重要作用。具体来说,key值用于以下两个目的:

  • 当多个进程需要访问同一个共享内存段时,它们可以使用相同的key值来标识这个共享内存段。
  • 如果一个共享内存段已经存在,并且其他进程想要访问它,那么只需要提供相同的key值即可找到该共享内存段。

  那在使用 shmget 函数之前,我们应该使用 ftok 函数生成key值,来表示这个共享内存段。由于是标示共享空间,所以应该确定唯一性。至于key的值是多少并不关键。那我们看一下ftok 函数的用法。具体如下:

参数说明:

  • pathname:一个包含一个现有文件的路径名,用于生成k值。最好是有权访问这个文件。
  • proj_id:不同的proj_id可以被用作区分不同类型的通信方式或不同的ipc资源,来生成不同的k值。其实就是一个任意整型值。

  我们再看一下其具体的例子:

#include #include #include int main(){    key_t key;    char *path = "./example.txt";    int proj_id = 0x66;    // 使用ftok函数生成k值    key = ftok(path, proj_id);    printf("Generated key: %d\n", key);    return 0;}

  另一个进程也可以用相同的方法生成相同的key值。ftok函数根据给定的路径名和proj_id生成k值。当路径名和proj_id相同时,生成的k值也相同。这是因为ftok函数内部使用了哈希运算,将路径名和proj_id转化为一个唯一的整数。尽管可能存在哈希冲突(即不同的路径名和proj_id生成相同的k值),但概率非常低。通常情况下,不同的进程可以使用相同的路径名和proj_id生成相同的k值是非常罕见的。即使出现相同的k值,由于进程间通信中还有其他参数的限制(如消息队列标识、共享内存标识等),不同进程之间的IPC通信仍然可以正常进行。  

  生成 key 值后,我们就可以用key值创建共享内存,或者来获取共享内存。下面我们看一下获取使用key值来获取共享内存的方法。

1、2、3 获取共享内存 shmget

  shmget 函数还可用来获取共享内存。当生成的key值已经有对应的共享内存时,shmget 函数就会返回这段共享内存的标识码。我么不只需要将第三个参数修改为0,就是来获取对应key值的共享内存。

1、3 demo 代码

  我们接下来写一段代码测试总结一下我们上面所学到的函数。下面为实例:

// Log.hpp#include #include #define Debug   0#define Notice  1#define Warning 2#define Error   3const std::string msg[] = {    "Debug",    "Notice",    "Warning",    "Error"};std::ostream &Log(std::string message, int level){    std::cout << " | " << (unsigned)time(nullptr) << " | " << msg[level] << " | " << message;    return std::cout;}// comm.hpp#pragma once#include #include #include #include #include #include #include #include #include #include #include #include "Log.hpp"using namespace std; #define PATH_NAME "/home/gtm"#define PROJ_ID 0x66#define SHM_SIZE 4096 //共享内存的大小,最好是页(PAGE: 4096)的整数倍#define FIFO_NAME "./fifo"// shmClient.cC#include"comm.hpp"int main(){    Log("child pid is : ", Debug) << getpid() << endl;    key_t k = ftok(PATH_NAME, PROJ_ID);    if (k < 0)    {        Log("create key failed", Error) << " client key : " << k << endl;        exit(1);    }    Log("create key done", Debug) << " client key : " << k << endl;    // 获取共享内存    int shmid = shmget(k, SHM_SIZE, 0);    if(shmid < 0)    {        Log("create shm failed", Error) << " client key : " << k << endl;        exit(2);    }    Log("create shm success", Error) << " client shmid : " << shmid << endl;    return 0;}// shmServer.cc#include "comm.hpp"string TransToHex(key_t k){    char buffer[32];    snprintf(buffer, sizeof buffer, "0x%x", k);    return buffer;}int main(){    // 我们之前为了通信,所做的所有的工作,属于什么工作呢:让不同的进程看到了同一份资源(内存)    // 1. 创建公共的Key值    key_t k = ftok(PATH_NAME, PROJ_ID);    assert(k != -1);    Log("create key done", Debug) << " server key : " << TransToHex(k) << endl;    // 2. 创建共享内存 -- 建议要创建一个全新的共享内存 -- 通信的发起者    int shmid = shmget(k, SHM_SIZE, IPC_CREAT | IPC_EXCL | 0666); //    if (shmid == -1)    {        perror("shmget");        exit(1);    }    Log("create shm done", Debug) << " shmid : " << shmid << endl;        return 0;}

  shmServer.cc文件中的代码是服务端代码。首先调用ftok函数生成一个唯一的键值,并将其转换为十六进制字符串表示。然后使用shmget函数创建一个共享内存段,创建时指定了IPC_CREAT标志,用于新建共享内存段。如果创建成功,返回一个共享内存标识符shmid。

  shmClient.cc文件中的代码是客户端代码。首先也是调用ftok函数生成一个唯一的键值。然后通过shmget函数打开已存在的共享内存段,打开时不需要指定IPC_CREAT标志,而是提供即将打开的共享内存段的键值和大小。如果打开成功,返回一个共享内存标识符shmid。

  Log.hpp文件定义了一个宏和一个Log函数。宏定义了四个日志级别,分别对应Debug、Notice、Warning和Error四个字符串。Log函数负责输出日志信息,接受一个字符串信息和一个日志级别参数。Log函数将时间戳、日志级别和消息内容输出到标准输出流中。

  上述代码就是完成了创建共享内存的功能,并且在其中打印了一些日志信息。我们不妨来看一下运行结果。具体如下图:

  我们发现对应的shmid是相同的,说明Server和Client确实获得了相同的共享内存块。他们所生成的key值相同吗?其实是相同的,如下图:

二、对共享内存进行相关操作 

2、1 查看/删除 共享内存资源

  当我们再次运行时,就会发生错误。具体如下图:

  为什么呢?原因是我们刚刚创建的共享内存依然存在。当进程结束时,共享内存并不会自动释放。为什么呢?我们可以认为共享内存是属于操作系统。所以共享内存的生命周期随操作系统!这时我们可以手动关闭共享内存。在关闭前首先要查看共享内存,指令:ipcs -m。具体如下图:

  当然,查到共享内存后,可以用指令进行删除。那么问题来了,使用key值删除呢?还是用shmid 进行删除呢?我们这里需要注意:共享内存中的shmid和key值是两个不同的概念

  1. shmid(Shared Memory ID)是共享内存的标识符,由操作系统分配,并作为一个非负整数对共享内存进行引用。在使用共享内存时,我们需要通过shmid来进行操作,如创建、附加、访问和删除等。shmid可以看作是内核用于标识某个特定共享内存段的一个唯一值

  2. key值是用户定义的一个标识符,通常是一个整数值。在创建共享内存时,我们可以使用ftok函数生成一个key值,以便其他进程可以通过这个key值来获取相同的共享内存区域。key值是用于标识共享内存的用户级别的标识符,不同于shmid,其值不受内核控制

  所以删除共享内存,我们使用的shmid。具体指令:ipcrm -m shmid。如下图:

  当我们删除共享内存后,再次进行查找发现就没有了,且程序能够正常运行。

2、2 共享内存挂接和访问

2、2、1 共享内存的挂接 shmat()

  在调用shmget()函数时,内核会在内部维护一个共享内存表格,其中包含了共享内存的相关信息,包括共享内存的大小、权限等。当调用成功后,将返回一个唯一的共享内存标识符,该标识符可以用于后续的共享内存操作。

  那么正常来说,我们访问共享内存是需要通过系统调用的。但是我们这里可以将内核级别的共享内存挂接到进程的地址空间。然后用户就可以直接进行访问

  进程可以使用系统提供的函数(如shmat())将自己的地址空间映射到共享内存。也可以理解为shmat()函数将共享内存附加到进程的虚拟地址空间中,使得进程可以访问该共享内存所指向的物理内存区域。具体用法如下:

  参数说明:

  • shm_id:共享内存标识符,通过调用 shmget 获取。
  • shm_addr:内存段的地址,通常传入 NULL,表示由系统自动选择一个适合的地址。
  • shmflg:控制共享内存段的附加方式和权限,可以使用 IPC_CREAT 标志创建新的共享内存段。通常传入0。

  返回值:

  • 如果成功,返回指向共享内存段第一个字节的指针;
  • 如果失败,返回 void * 类型的错误值 -1

  其实我们看完其使用方法后,有没有发现与 malloc 很相似。malloc 申请空间成功后,会返回所申请空间的起始地址。否则就会返回NULL。shmat 与其确实有些相似。我们可结合如下例子一起理解:

#include #include #include #include int main() {    int shm_id;    key_t key;    int *shared_memory;    // 获取共享内存标识符    key = ftok("。/file", 0x66);    shm_id = shmget(key, sizeof(int), IPC_CREAT | 0666);        // 将共享内存段附加到进程的地址空间中    shared_memory = shmat(shm_id, NULL, 0);        // 访问共享内存    printf("共享内存中的值为:%d\n", *shared_memory);        // 分离共享内存段    shmdt(shared_memory);        return 0;}

  我们也看到了最后是有一个去关联的 shmdt 函数。参数就是我们所获取的共享内存的起始地址,这里就不再过多解释此函数

  这里有会有一个问题:将内核级别的共享内存挂接到进程地址空间的哪里了呢?我们看如下图:

   我们之前学进程地址空间时,知道堆和栈的中间有大量的镂空,而这段位置就是内核级别的共享内存所挂接到的位置!

2、2、2 共享内存的访问

  到这里,我们已经学习了共享内存的大部分内容。只差对共享内存的访问了。当我们对共享内存进行挂接后, 就可以得到共享内存挂接后的起始地址。我们用户可以对其进行直接访问(写入/读取)。我们给出如下伪代码:

    // shmServer.cpp    char *shmaddr = (char *)shmat(shmid, nullptr, 0);    Log("attach shm done", Debug) << " shmid : " << shmid << endl;    for(;;)    {        printf("%s\n", shmaddr);        if(strcmp(shmaddr, "quit") == 0) break;        sleep(1);    }    // shmClient.cpp      // 挂接并获得共享内存起始地址    char *shmaddr = (char *)shmat(shmid, nullptr, 0);    if(shmaddr == nullptr)    {        Log("attach shm failed", Error) << " client key : " << k << endl;        exit(3);    }    char a = 'a';    for(; a <= 'c'; a++)    {        // 我们是每一次都向shmaddr[共享内存的起始地址]写入        snprintf(shmaddr, SHM_SIZE - 1,\            "hello server, 我是其他进程,我的pid: %d, inc: %c\n",\            getpid(), a);        sleep(3);    }

  对上述代码是一个使用共享内存进行进程间通信的伪代码。下面对代码进行详解:

  1. 首先,在服务端(shmServer.cpp)中,通过shmat函数将共享内存连接到当前进程的地址空间。shmat函数的第一个参数是共享内存的标识符shmid,第二个参数为NULL表示让系统自动选择合适的地址分配给共享内存,第三个参数为0表示以默认权限进行操作。连接完成后,返回共享内存的起始地址,并赋值给shmaddr指针。

  2. 服务器端的for循环中,通过printf函数将shmaddr指向的共享内存内容输出到标准输出(读取)。然后通过strcmp函数判断共享内存中的内容是否为"quit",如果是,则跳出循环,结束程序。否则,通过sleep函数暂停1秒钟。

  3. 在客户端(shmClient.cpp)中,同样通过shmat函数连接到共享内存,并将共享内存的起始地址赋给shmaddr指针。若连接失败(shmaddr为nullptr),则输出错误信息并退出程序。

  4. 客户端的for循环中,使用snprintf函数将格式化的字符串写入shmaddr指向的共享内存中(写入)。该字符串包含了客户端进程的PID(进程标识符)和一个递增的字符,以展示多次写入的内容。然后通过sleep函数暂停3秒钟。

  运行结果如下:

  我们通过运行结果发现:在客户端没有写入的情况下,服务端进行读取时也会读到内容。读到的是空字符串(共享内存默认会初始化为0)。我们发现共享内存的读写并没有访问控制。我们知道命名管道通信是由访问控制的。但是当一个进程写入时,另一个就能够马上看到写入的内容。所以共享内存是所有进程间通信(IPC),速度最快的!不需要过多的拷贝!!(不需要将数据给操作系统)。如果我想一定程度的访问控制呢?可以在共享内存读写的过程中加入命名管道来控制。

2、3 删除共享内存 shmctl 

  上面我们了解了可以使用linux指令对共享内存进行删除,我们也可以使用系统调用 shmctl()函数 对其进行删除。具体使用如下:

 参数说明:

  • shmid:共享内存标识符,通过shmget函数获取得到。
  • cmd:表示对共享内存进行的操作类型,可以选择的参数有:
    • IPC_STAT:获取共享内存的状态信息,将共享内存的属性保存在buf所指向的结构体中。
    • IPC_SET:设置共享内存的属性,使用buf所指向的结构体中的值进行设置。
    • IPC_RMID:删除共享内存。
  • buf:指向一个struct shmid_ds结构体的指针,用于存储共享内存的属性信息。通常使用nullptr。

  shmctl函数可以用于对共享内存段进行控制操作。它能够实现共享内存的创建、删除、以及获取和修改共享内存的属性。但是我们该函数最常用删除共享内存。使用IPC_RMID操作可以删除指定的共享内存段,并释放系统资源。这个操作会立即删除共享内存段,以及与它关联的任何进程中的键和id

三、完整共享内存通信 demo 代码

3、1 Log.hpp 日志

  

#include #include #define Debug   0#define Notice  1#define Warning 2#define Error   3const std::string msg[] = {    "Debug",    "Notice",    "Warning",    "Error"};std::ostream &Log(std::string message, int level){    std::cout << " | " << (unsigned)time(nullptr) << " | " << msg[level] << " | " << message;    return std::cout;}

3、2 comm.hpp

#pragma once#include #include #include #include #include #include #include #include #include #include #include #include "Log.hpp"using namespace std; //不推荐#define PATH_NAME "/home/whb"#define PROJ_ID 0x66#define SHM_SIZE 4096 //共享内存的大小,最好是页(PAGE: 4096)的整数倍#define FIFO_NAME "./fifo"class Init{public:    Init()    {        umask(0);        int n = mkfifo(FIFO_NAME, 0666);        assert(n == 0);        (void)n;        Log("create fifo success",Notice) << "\n";    }    ~Init()    {        unlink(FIFO_NAME);        Log("remove fifo success",Notice) << "\n";    }};#define READ O_RDONLY#define WRITE O_WRONLYint OpenFIFO(std::string pathname, int flags){    int fd = open(pathname.c_str(), flags);    assert(fd >= 0);    return fd;}void Wait(int fd){    Log("等待中....", Notice) << "\n";    uint32_t temp = 0;    ssize_t s = read(fd, &temp, sizeof(uint32_t));    assert(s == sizeof(uint32_t));    (void)s;}void Signal(int fd){    uint32_t temp = 1;    ssize_t s = write(fd, &temp, sizeof(uint32_t));    assert(s == sizeof(uint32_t));    (void)s;    Log("唤醒中....", Notice) << "\n";}void CloseFifo(int fd){    close(fd);}

3、3 shmClient.cpp

#include "comm.hpp"int main(){    Log("child pid is : ", Debug) << getpid() << endl;    key_t k = ftok(PATH_NAME, PROJ_ID);    if (k < 0)    {        Log("create key failed", Error) << " client key : " << k << endl;        exit(1);    }    Log("create key done", Debug) << " client key : " << k << endl;    // 获取共享内存    int shmid = shmget(k, SHM_SIZE, 0);    if(shmid < 0)    {        Log("create shm failed", Error) << " client key : " << k << endl;        exit(2);    }    Log("create shm success", Error) << " client key : " << k << endl;    // sleep(10);    char *shmaddr = (char *)shmat(shmid, nullptr, 0);    if(shmaddr == nullptr)    {        Log("attach shm failed", Error) << " client key : " << k << endl;        exit(3);    }    Log("attach shm success", Error) << " client key : " << k << endl;    int fd = OpenFIFO(FIFO_NAME, WRITE);    // client将共享内存看做一个char 类型的buffer    while(true)    {        ssize_t s = read(0, shmaddr, SHM_SIZE-1);        if(s > 0)        {            shmaddr[s-1] = 0;            Signal(fd);            if(strcmp(shmaddr,"quit") == 0) break;        }    }    CloseFifo(fd);    // 去关联    int n = shmdt(shmaddr);    assert(n != -1);    Log("detach shm success", Error) << " client key : " << k << endl;    return 0;}

3、4 shmServer.cpp

#include "comm.hpp"Init init; string TransToHex(key_t k){    char buffer[32];    snprintf(buffer, sizeof buffer, "0x%x", k);    return buffer;}int main(){    // 1. 创建公共的Key值    key_t k = ftok(PATH_NAME, PROJ_ID);    assert(k != -1);    Log("create key done", Debug) << " server key : " << TransToHex(k) << endl;    // 2. 创建共享内存 -- 建议要创建一个全新的共享内存 -- 通信的发起者    int shmid = shmget(k, SHM_SIZE, IPC_CREAT | IPC_EXCL | 0666); //    if (shmid == -1)    {        perror("shmget");        exit(1);    }    Log("create shm done", Debug) << " shmid : " << shmid << endl;    // 3. 将指定的共享内存,挂接到自己的地址空间    char *shmaddr = (char *)shmat(shmid, nullptr, 0);    Log("attach shm done", Debug) << " shmid : " << shmid << endl;        int fd = OpenFIFO(FIFO_NAME, READ);    for(;;)    {        Wait(fd);        // 临界区        printf("%s\n", shmaddr);        if(strcmp(shmaddr, "quit") == 0) break;        // sleep(1);    }    // 4. 将指定的共享内存,从自己的地址空间中去关联    int n = shmdt(shmaddr);    assert(n != -1);    (void)n;    Log("detach shm done", Debug) << " shmid : " << shmid << endl;    // 5. 删除共享内存,IPC_RMID即便是有进程和当下的shm挂接,依旧删除共享内存    n = shmctl(shmid, IPC_RMID, nullptr);    assert(n != -1);    (void)n;    Log("delete shm done", Debug) << " shmid : " << shmid << endl;    CloseFifo(fd);    return 0;}

  上述共享内存代码是结合了命名管道通信进行了访问控制

来源地址:https://blog.csdn.net/weixin_67596609/article/details/132754559

--结束END--

本文标题: 【Linux从入门到精通】通信 | 共享内存(System V)

本文链接: https://lsjlt.com/news/422170.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

猜你喜欢
  • 【Linux从入门到精通】通信 | 共享内存(System V)
        本篇文章接着上篇文章通信 | 管道通信(匿名管道 & 命名管道)进行讲解。本篇文章的中点内容是共享内存。 文章目录  一、初识与创建共享内存 1、1 什么是共享内存 1、2 共享内存函数 1、2、1 创建共享内存 ...
    99+
    2023-10-01
    linux 运维 通信 共享内存
  • 【Linux】system V 共享内存
    文章目录 system V1. 共享内存原理第一阶段原理第二阶段原理 2. 直接写代码--编写代码进行原理介绍shmget函数ftok函数key值用法 1. 创建key值2. 创建共享内存 获取共享内存3. 将自己和共...
    99+
    2023-08-21
    linux 服务器 运维
  • 【Linux从入门到精通】信号(信号保存 & 信号的处理)
      本篇文章接着信号(初识信号 & 信号的产生)进行讲解。学完信号的产生后,我们也了解了信号的一些结论。同时还留下了很多疑问: 上篇文章所说的所有信号产生,最终都要有OS来进行执行,为什么呢?OS是进程的管理者。信号的处理是否是立即...
    99+
    2023-09-29
    运维 linux 信号处理
  • SQLServer从入门到精通
    1、数据分页OFFSET:指定在从查询表达式中返回行之前,将跳过的行数。FETCH:指定在OFFSET子句后,将返回的行数。OFFSET是页号的同义词,FRTCH则代表每页显示的行数。select...
    99+
    2024-04-02
  • GNS3从入门到精通
    GNS3是一款优秀的具有图形化界面的模拟器。可以运行在多平台上(Windows,Linux,MacOS等)。其最大的特点就是搭建拓扑极其简单,且支持保存startup-config,供下次实验中继续导入使用,而且所有设备导入时间在1分钟内即...
    99+
    2023-01-31
    入门
  • 解决Linux system v 共享内存问题
    system v 共享内存 #include <sys/types.h> #include <sys/shm.h> int shmget(key_t key, size_t size, int...
    99+
    2022-06-04
    Linux system v 共享内存 Linux 共享内存
  • J2EE 5从入门到精通
    J2EE 5从入门到精通Java 2 Enterprise Edition (J2EE)入门学习指南: Detail:J2EE 5从入门到精通[@more@]...
    99+
    2023-06-03
  • Node.js OAuth 从入门到精通
    ...
    99+
    2024-04-02
  • Linux之进程间通信(共享内存【mmap实现+系统V】)
    目录共享内存mmap()及其相关的系统调用mmap()munmap()共享内存的使用命令管理共享内存总结共享内存 共享内存可以说是最有用的进程间通信方式,也是最快的IPC形式,两个不同的进程A、B共享内存的意思就是:同一...
    99+
    2023-03-23
    Linux进程间通信 Linux共享内存 Linux进程
  • Go通道channel通过通信共享内存
    目录引言通道的声明与创建接收 & 发送数据引言 不要通过共享内存来通信 应该通过通信来共享内存 这句话有网友的解释如下: 这句俏皮话具体说来就是,不同的线程不共享内存不用锁,...
    99+
    2024-04-02
  • 【Linux】进程间通信(万字详解)—— 匿名管道 | 命名管道 | System V | 共享内存
    🌈欢迎来到Linux专栏~~进程通信 ...
    99+
    2023-08-22
    linux 服务器 unix
  • python从入门到精通(DAY 1)
    1、要点 (1) 在C语言中没有字符串,只有字符, 在python中的字符串hello,在C语言中是以字符数组在内存存放['h','e','l','l','o'],如果对字符串修改,则是在内存中...
    99+
    2022-06-04
    入门 python DAY
  • python从入门到精通(DAY 2)
    1、字典复制: dict = {'name':'wang', 'sex':'m', 'age':34, 'job':'it'} info = dict ##别名 (二个字典指向内存的同一地址...
    99+
    2022-06-04
    入门 python DAY
  • python从入门到精通(DAY 3)
    要求:编写登陆接口 输入用户名密码 认证成功后显示欢迎信息 输错三次后锁定 针对此实例写了有二种类型的脚本,略有不同,具体如下: 帐号文件account.txt内容如下: sam 123 david 12...
    99+
    2022-06-04
    入门 python DAY
  • Shell编程:从入门到精通
    Shell编程是一种非常实用的技能,可以帮助我们完成各种自动化任务,提高工作效率。本文将带领大家从入门到精通Shell编程,让你可以更好地利用Shell脚本编写工具,提升自己的技能水平。 一、基础知识 Shell是一种脚本语言,它可以直接...
    99+
    2023-09-10
    javascript shell linux
  • wpf从入门到精通教程
    WPF(Windows Presentation Foundation)是微软开发的一种基于.NET Framework的桌面应用程序开发框架。它提供了丰富的用户界面元素、数据绑定和动画等功能,使得开发者可以轻松地创建高质量的桌面应用程序。...
    99+
    2023-10-27
    WPF 入门到精通
  • 学习Golang:从入门到精通
    在当今信息技术发展迅速的时代背景下,编程语言的选择变得越来越重要。Golang作为一种由Google开发的现代化编程语言,在其诞生的短短几年里便迅速崛起并受到了广泛关注。 Golang...
    99+
    2024-02-24
    学习 golang 进阶 网络编程
  • python怎么共享内存通信
    在Python中,可以使用多种方式来实现进程间的共享内存通信,下面是一些常用的方法: 使用`multiprocessing`模块中...
    99+
    2023-10-25
    python
  • 深入了解PHP:从入门到精通
    深入了解PHP:从入门到精通引言:PHP是一种广泛应用于web开发的服务器端脚本语言,它简单易学,适用于初学者,也提供了丰富的功能和扩展性,能够满足复杂的开发需求。本文将从入门到精通,通过具体的代码示例,带您逐步了解PHP的各个方面。一、基...
    99+
    2023-12-19
    PHP 入门 精通
  • python 读取xml从入门到精通
      XML (Extensible Markup Language),可扩展标记语言,是一种被广泛应用于网络上的文件格式。在互联网上,网页里的信息都以 XML格式存储,例如 HTML、 CSV、 JSON等。随着电子商务的发展,人们需要在...
    99+
    2023-09-16
    python xml 开发语言
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作