基于多进程并发-进程通讯之管道(pipe)

2023-10-31

一、管道(pipe)

所谓的管道,就是内核⾥⾯的⼀串缓存(Pipe)。一个进程从管道的⼀端写⼊的数据,实际上是缓存在内核中的,另⼀端读取,也就是从内核中读取这段数据。

特性:

  • 有两种类型的管道:匿名管道,有名管道(也叫命名管道)
  • 简单实现
  • 有大小限制
  • 无格式的字节流数据
  • 用户态与内核态之间数据拷贝
  • 匿名管道:单向通信、不可跨PC
  • 有名管道:双向通信、可跨PC
  • 自带同步与互斥
  • 内核里面的⼀串缓存(Pipe)

二、匿名管道

在这里插入图片描述

1、简介

匿名管道只能用于父子进程间通信 ,不能跨网络通信,并且通信是单向。另外,管道传输的数据是⽆格式的流且⼤⼩受限。

正常情况下,控制台进程的输输入出是在控制台窗口的,但是如果我们在创建子进程的时候指定了其输入输出,那么子进程就会从我们的管道读数据,把输出数据写到我们指定的管道。
这就是我们代码中重定向标准输入的原因,否则system(“pause”)会无效。

2、父子进程:匿名管道的通信过程?

父进程写管道、子进程读管道,过程如下。

  • 1、父进程,CreatePipe()创建管道会得到两个句柄,即,管道的读句柄和管道的写句柄。
  • 2、父进程执行CreateProcess()启动子进程时,可以把句柄传(比如把读句柄传给子进程)递给子进程,写句柄父进程自己保存。
  • 3、父进程调用调用WriteFile()将数据写入到管道。
  • 4、子进程调用GetStdHandle()取得管道的读句柄,
  • 5、然后,子进程ReadFile()从管道读取出数据。

这样就做到了两个进程各有一个句柄(父进程写句柄、子进程读句柄),两个进程就可以通过各⾃的句柄 写⼊和读取同⼀个管道⽂件实现跨进程通信。

  • 以上流程说的是父进程写管道,子进程读管道。当然,也可以反过来,子进程写、父进程读,那就是父进程把写句柄给子进程,父进程保存读句柄)。

3、相关函数

3.1、创建管道CreatePipe

BOOL CreatePipe(
PHANDLE hReadPipe; //指向管道读句柄
PHANDLE hWritePipe; //指向管道写句柄
LPSECURITY_ATTRIBUTES lpPipeAttributes;  //指向管道安全属性
DWORD nSize; //管道大小
)

3.2、写入管道WriteFile

BOOL WriteFile(
               HANDLE  hFile,//文件句柄
               LPCVOID lpBuffer,//数据缓存区指针
               DWORD   nNumberOfBytesToWrite,//要写的字节数
               LPDWORD lpNumberOfBytesWritten,//用于保存实际写入字节数的存储区域的指针
               LPOVERLAPPED lpOverlapped//OVERLAPPED结构体指针
);

3.3、读取管道ReadFile

BOOL ReadFile(
    HANDLE hFile, //文件的句柄
    LPVOID lpBuffer, //接收数据的缓冲区
    DWORD nNumberOfBytesToRead,    //读取的字节数
    LPDWORD lpNumberOfBytesRead,    //指向实际读取字节数的指针
    LPOVERLAPPED lpOverlapped
    //如文件打开时指定了FILE_FLAG_OVERLAPPED,那么必须,用这个参数引用一个特殊的结构。
    //该结构定义了一次异步读取操作。否则,应将这个参数设为NULL
);

3.4、获取句柄GetStdHandle
该函数用于取得指定的标准设备的句柄(标准输入,标准输出或标准错误),本文demo用于:子进程获取父进程传递的读句柄。

HANDLE WINAPI GetStdHandle( _In_ DWORD nStdHandle);

参数 含义
STD_INPUT_HANDLE 标准输入句柄
STD_OUTPUT_HANDLE 标准输出句柄
STD_ERROR_HANDLE 标准错误句柄

4、demo

  • 父进程
//main.cpp
#include <windows.h> 
#include "iostream"
#define BUFSIZE 4096 
using namespace std;
 
int main(int argc, char* argv[])
{
    cout << "\n ** This is a message from the father process. ** \n";

    cout << "第一步:创建管道" << endl;

    // Set the bInheritHandle flag so pipe handles are inherited. 
    SECURITY_ATTRIBUTES saAttr;
    saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
    saAttr.bInheritHandle = TRUE;
    saAttr.lpSecurityDescriptor = NULL;

    // Create a pipe for the child process's STDIN. 
    HANDLE handle_read;
    HANDLE handle_write;
    bool ret = CreatePipe(&handle_read, &handle_write, &saAttr, 0);
    if (!ret)
    {
        cout << "创建进程失败:create pipe fail" << endl;
    }

    //设置写句柄不可以被子进程继承,不设置也不影响。 Ensure the write handle to the pipe for STDIN is not inherited. 
    if (!SetHandleInformation(handle_write, HANDLE_FLAG_INHERIT, 0))
    {
        cout << "设置句柄失败:set handle fail!" << endl;
    }

    cout << "第一步:子进程、设置管道句柄的继承" << endl; 
    {
        // Create the child process. 

        char cmdline[] = "childprocess.exe";
        PROCESS_INFORMATION piProcInfo;
        // Set up members of the PROCESS_INFORMATION structure. 
        ZeroMemory(&piProcInfo, sizeof(PROCESS_INFORMATION));

        // Set up members of the STARTUPINFO structure. // This structure specifies the STDIN handles for redirection.
        STARTUPINFO si;
        ZeroMemory(&si, sizeof(STARTUPINFO));
        si.cb = sizeof(STARTUPINFO);
        si.hStdInput = handle_read; //把管道的读句柄传给子进程
        si.dwFlags |= STARTF_USESTDHANDLES;

        // Create the child process.
        ret = CreateProcess(NULL, cmdline, NULL, NULL, TRUE, CREATE_NEW_CONSOLE, NULL, NULL, &si, &piProcInfo);
        if (!ret)
            cout << "创建子进程失败:create child process faile!";
        else
        {
            cout << "创建子进程成功:create child process sucess!";
            // Close handles to the child process and its primary thread.
            CloseHandle(piProcInfo.hProcess);
            CloseHandle(piProcInfo.hThread);

            CloseHandle(handle_read);
        }
    }

    cout << "第三步:向管道中写入数据:write to pipe." << endl;
    {
        // write contents to the pipe for the child's STDIN.

        DWORD len;
        char chBuf[BUFSIZE] = " hello pipe";
        for (int i = 0; i < 10; i++)
        {
            bool ret = WriteFile(handle_write, chBuf, sizeof(chBuf), &len, NULL);//子进程读了后,父进程才可以继续写入管道
            if (!ret)
            {
                cout << "写入管道数据失败。i=" << i << endl;
                break;
            }
            else 
            {
                cout << "send data " << i << " is:" << chBuf << endl;
            }
            
        }
        cout << "写入管道数据结束。" << endl;
        // Close the pipe handle so the child process stops reading. 
        if (!CloseHandle(handle_write))
            cout << "colse handle fail" << endl;
    }
    return 0;
}
  • 子进程
// main.cpp
#include <windows.h>
#include"iostream"
#define BUFSIZE 4096 
using namespace std;
 
int main(int argc, char* argv[])
{ 
    cout<<"\n ** This is a message from the child process. ** \n";
   CHAR chBuf[BUFSIZE]; 
   DWORD len; 
   HANDLE handle_read; 
 
   handle_read = GetStdHandle(STD_INPUT_HANDLE);
   if (handle_read == INVALID_HANDLE_VALUE)
      ExitProcess(1); 
 
   for (int i = 0;i<5;i++)
   { 
   // Read from standard input and stop on error or no data.
      bool ret = ReadFile(handle_read, chBuf, BUFSIZE, &len, NULL);
      if (!ret || len == 0)
      {
          cout << "读取数据失败" << endl;
          break;
      }

      cout << "receive data "<<i<<" is:" << chBuf << endl;
   } 
   cout << "读取数据结束" << endl;
   Sleep(5000);
   freopen("CON", "r", stdin);    // 重定向输入,否则system("pause")会无效
   //CloseHandle(handle_read);
   system("pause");
   return 0;
}

5、结果

  • 父进程
    在这里插入图片描述
  • 子进程
    在这里插入图片描述
  • 后记
    1.子进程取出管道中的数据后,父进程才可以继续往管道中写入数据
    2.父进程在输入第5个send data后,子进程并没有读取。但是当子的sleep结束后,不知什么原因,不确定第5次的输入是被谁读走的。
    3.子进程的sleep函数之前的输出如下
    在这里插入图片描述

三、有名管道

在这里插入图片描述

1、简介

命名管道,顾名思义,这个管道肯定是有名字的。通过管道的名字来确保多个进程访问同一个管道。事实上,命名管道不仅可在同一台计算机的不同进程之间传输数据,甚至能在跨越一个网络的不同计算机的不同进程之间,支持可靠的、单向或双向的数据通信。

命名管道的服务器和客户机的区别在于:
服务器是唯一一个有权创建命名管道的进程,也只有他才能接受管道客户机的连接请求。
而客户机只能同一个线程的命名管道服务器建立连接。

  • 命名管道具有很好的使用灵活性,表现在:
      1) 既可用于本地,又可用于网络。
      2) 可以通过它的名称而被引用。
      3) 支持多客户机连接。
      4) 支持双向通信。
      5)支持异步重叠I/O操作

2、两个进程间:命名管道的工作过程

  • 服务器
    命名管道服务器,步骤如下:
    1)使用API函数CreateNamedPipe,创建一个命名管道实例句柄。
    2)使用API函数ConnectNamedPipe,在命名管道实例上监听客户机连接请求。
    3)分别使用ReadFile和WriteFile这两个API函数,从客户机接收数据,或将数据发给客户机。
    4)使用API函数DisconnectNamedPipe,关闭命名管道连接。
    5)使用API函数CloseHandle,关闭命名管道实例句柄。
  • 客户端
    命名管道客户机,步骤如下:
    1)调用API函数WaitNamedPipe,等候一个命名管道实例可供使用。
    2)调用API函数CreateFile,打开命名管道实例并建立连接。
    3)调用API函数WriteFile和ReadFile,分别向服务器发送数据和从中接收数据。
    4)调用API函数CloseHandle,关闭打开的命名管道会话。

3、相关函数

3.1、创建命名管道CreateNamedPipe
创建命名管道的实例,并返回后续管道操作的句柄。

HANDLE CreateNamedPipeA(
  [in]           LPCSTR                lpName,
  [in]           DWORD                 dwOpenMode,
  [in]           DWORD                 dwPipeMode,
  [in]           DWORD                 nMaxInstances,
  [in]           DWORD                 nOutBufferSize,
  [in]           DWORD                 nInBufferSize,
  [in]           DWORD                 nDefaultTimeOut,
  [in, optional] LPSECURITY_ATTRIBUTES lpSecurityAttributes
);

CreateNamedPipe函数接口中的第一个参数lpName: .\pipe\pipename, 必须为这种格式。中间的“.”表示本地机器,如果要跟远程机器建立连接,则需要设定远程服务器的名字。

3.2、监听请求ConnectNamedPipe
在命名管道实例上监听客户机连接请求。

BOOL ConnectNamedPipe(
  [in]                HANDLE       hNamedPipe,
  [in, out, optional] LPOVERLAPPED lpOverlapped
);

3.3、等候一个命名管道实例WaitNamedPipe
等到超时间隔过或指定命名管道的实例可用于连接

BOOL ConnectNamedPipe(
  [in]                HANDLE       hNamedPipe,
  [in, out, optional] LPOVERLAPPED lpOverlapped
);

4、demo

  • 服务端
#include <iostream>
#include <windows.h>
using namespace std;

int main()
{
	printf("创建命名管道并等待连接\n");

	char pipeName[] = "\\\\.\\Pipe\\mypipe";
	HANDLE hPipe = CreateNamedPipe(pipeName, PIPE_ACCESS_DUPLEX, PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT
		, PIPE_UNLIMITED_INSTANCES, 0, 0, NMPWAIT_WAIT_FOREVER, 0);


	//waiting to be connected
	if (ConnectNamedPipe(hPipe, NULL) != NULL)
	{
		printf("连接成功,开始发送数据\n");

		DWORD    dwWrite;
		const char* pStr = "data from server";
		if (!WriteFile(hPipe, pStr, strlen(pStr), &dwWrite, NULL))
		{
			cout << "write failed..." << endl << endl;
			return 0;
		}
		cout << "sent data: " << endl << pStr << endl << endl;
	}

	DisconnectNamedPipe(hPipe);
	CloseHandle(hPipe);//关闭管道
	printf("关闭管道\n");
	system("pause");
}


  • 客户端
// ClientPip.cpp 

#include <iostream>
#include <windows.h>
using namespace std;
#define BUFSIZE 5


int main()
{

	printf("命名管道:客户端上线\n");
	printf("按任意键以开始连接命名管道\n");
	getchar();
	printf("开始等待命名管道\n");

	char pipeName[] = "\\\\.\\Pipe\\mypipe";
	if (WaitNamedPipe(pipeName, NMPWAIT_WAIT_FOREVER) == FALSE)
		return 0;

	printf("打开命名管道\n");
	HANDLE hPipe = CreateFile(pipeName, GENERIC_READ | GENERIC_WRITE, 0,
		NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);

	if ((long)hPipe == -1)
		return 0;


	//接收服务端发回的数据
	BOOL fSuccess = false;
	DWORD len = 0;
	char buffer[BUFSIZE];
	string recvData = "";
	do
	{
		fSuccess = ReadFile(hPipe, buffer, BUFSIZE * sizeof(char), &len, NULL);
		char buffer2[BUFSIZE + 1] = { 0 };
		memcpy(buffer2, buffer, len);
		recvData.append(buffer2);
		if (!fSuccess || len < BUFSIZE)
			break;
	} while (true);

	cout << "recv data:" << endl << recvData.c_str() << endl << endl;

	FlushFileBuffers(hPipe);
	DisconnectNamedPipe(hPipe);
	CloseHandle(hPipe);

	system("pause");
	return 0;
}

5、输出

在这里插入图片描述

如有错误或不足欢迎评论指出!创作不易,转载请注明出处。如有帮助,记得点赞关注哦(⊙o⊙)
更多内容请关注个人博客:https://blog.csdn.net/qq_43148810

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

基于多进程并发-进程通讯之管道(pipe) 的相关文章

  • clang 格式换行符在错误的位置

    给出以下代码行 get abc manager get platform status abc platform status sw update status fill update status actions allowed stat
  • 如何使用 zlib 制作 .zip 文件

    我正在阅读zlib的文档 它相当详细 但我读到了这一行 输出数据将位于zlib格式 与 gzip 或zip formats http www zlib net zlib how html http www zlib net zlib how
  • 将字节数组转换为托管结构

    更新 这个问题的答案帮助我编写了开源项目GitHub 上的 AlicanC 现代战争 2 工具 https github com AlicanC AlicanC s Modern Warfare 2 Tool 你可以看到我是如何阅读这些数据
  • 在 C# 中生成 HMAC-SHA1

    我正在尝试使用 C 来使用 REST API API 创建者提供了以下用于 hmac 创建的伪代码 var key1 sha1 body var key2 key1 SECRET KEY var key3 sha1 key2 var sig
  • 如何尝试/捕获所有异常

    我正在完成由其他人启动的 UWP 应用程序 该应用程序经常崩溃 我总是陷入困境应用程序 at if global System Diagnostics Debugger IsAttached global System Diagnostic
  • C# 正则表达式用于查找 中具有特定结尾的链接

    我需要一个正则表达式模式来查找字符串 带有 HTML 代码 中的链接 以获取文件结尾如 gif 或 png 的链接 示例字符串 a href site com folder picture png target blank picture
  • CultureInfo 的实例(来自相同的文化)根据操作系统而变化

    我有一个网站 上面写着这样的日期 CultureInfo cultureInfo CultureInfo GetCultures CultureTypes AllCultures FirstOrDefault c gt string Equ
  • 在 C# Winforms 应用程序中嵌入 Windows XP 主题

    我有一个旧版 C Windows 窗体应用程序 其布局是根据 Windows XP 默认主题设计的 由于需要将其作为 Citrix 应用程序进行分发 该应用程序现在看起来像经典主题应用程序 因为 Citrix 不鼓励使用主题系统服务 所以
  • 如何使用MySqlCommand和prepare语句进行多行插入?(#C)

    Mysql 给出了如何使用准备语句和 NET 插入行的示例 http dev mysql com doc refman 5 5 en connector net programming prepared html http dev mysq
  • 对 boost 库的依赖项没有完整路径

    我已经成功构建了动态库 依赖于使用自定义前缀构建和安装的 boost 库 b2 install prefix PREFIX 然而 当我跑步时otool L在我的库中 我得到如下输出 libboost regex dylib compatib
  • HttpWebRequest vs Webclient(特殊场景)

    我知道这个问题之前已经回答过thread https stackoverflow com questions 1694388 webclient vs httpwebrequest httpwebresponse 但我似乎找不到详细信息 在
  • 两种类型的回发事件

    1 我发现了两篇文章 每篇文章对两种类型的回发事件的分类都略有不同 一位资源说两种类型的回发事件是Changed事件 其中控件实现 IPostbackDataHandler 当数据在回发之间更改时触发 然后Raised事件 其中控件实现 I
  • 分配器感知容器和propagate_on_container_swap

    The std allocator traits模板定义了一些常量 例如propagate on container copy move assign让其他容器知道它们是否应该在复制或移动操作期间复制第二个容器的分配器 我们还有propag
  • 如何随着分辨率的变化自动调整大小和调整表单控件

    我注意到某些应用程序会更改控件的位置以尽可能适应当前的分辨率 例如 如果窗口最大化 则控件的设置方式应使整个 GUI 看起来平衡 是否可以使用 C 在 Visual studio 2010 中制作或实现此功能 Use Dock http m
  • 二叉树中的 BFS

    我正在尝试编写二叉树中广度优先搜索的代码 我已将所有数据存储在队列中 但我不知道如何访问所有节点并消耗它们的所有子节点 这是我的 C 代码 void breadthFirstSearch btree bt queue q if bt NUL
  • asp.net网格分页的SQL查询

    我在用iBatis and SQLServer 使用偏移量和限制进行分页查询的最佳方法是什么 也许我添加该列ROW NUMBER OVER ORDER BY Id AS RowNum 但这只会阻止简单查询的数据访问 在某些情况下 我使用选择
  • 使用 iTextSharp 5.3.3 和 USB 令牌签署 PDF

    我是 iTextSharp 和 StackOverFlow 的新手 我正在尝试使用外部 USB 令牌在 C 中签署 PDF 我尝试使用从互联网上挖掘的以下代码 Org BouncyCastle X509 X509CertificatePar
  • 从 Delphi 调用 C# dll

    我用单一方法编写了 Net 3 5 dll 由Delphi exe调用 不幸的是它不起作用 步骤 1 使用以下代码创建 C 3 5 dll public class MyDllClass public static int MyDllMet
  • 如何引用解决方案之外的项目?

    我有一个 Visual Studio C 解决方案 其中包含一些项目 其中一个项目需要引用另一个不属于解决方案的项目 一开始我引用了dll
  • OSError: [WinError 193] %1 不是有效的 Win32 应用程序,同时使用 CTypes 在 python 中读取自定义 DLL

    我正在尝试编写用 python 封装 C 库的代码 我计划使用 CTypes 来完成此操作 并使用 Visual Studio 来编译我的 DLL 我从一个简单的函数开始 在 Visual Studio 内的标头中添加了以下内容 然后将其构

随机推荐

  • 如何在sublime Text3实时运行js代码?

    安装Node js https nodejs org en 为sublime text3添加编译系统 Tools gt Build System gt New Build System 在打开的界面中添加 cmd node file sel
  • UPnP协议学习

    UPnP架构定义了两种类型的设备 控制设备 controlled devices 和控制点 control points 控制设备扮演服务器的角色 响应控制点的请求 控制点和控制设备都能在各种平台包括个人电脑和嵌入式设备中实现 多个控制设备
  • C#8.0本质论第四章--操作符和控制流程

    C 8 0本质论第四章 操作符和控制流程 4 1操作符 有些操作符以符号的形式出现 例如 或者 等 而另一些操作符则为关键词 例如default和is 4 1 1一元正负操作符 一元正操作符 对值几乎没有影响 它在C 中是多余的 4 1 2
  • 组织机构代码输入测试用例_测试代码以用于过大的输入

    组织机构代码输入测试用例 在编写单元测试时 我们主要关注业务的正确性 我们将竭尽所能 开开心心地走在最前沿 我们有时会进行微基准测试并衡量吞吐量 但是经常遗漏的一个方面是当输入过大时我们的代码如何表现 我们测试了如何处理正常的输入文件 格式
  • MES系统介绍

    MES系统是什么 能解决企业管理中的什么问题 史上最全MES生产管理系统介绍 傲鹏MES供应商内部培训资料 错过了就没有了 一 MES系统介绍1 什么是MES系统 中文全称 制造执行系统 英文全称 manufacturing executi
  • 基于x86架构的CentOS7虚拟机通过qemu安装ARM架构CentOS7虚拟机_centos7 arm 网络配置

    原文连接 基于x86架构的CentOS7虚拟机通过qemu安装ARM架构CentOS7虚拟机 centos7 arm redrose2100的博客 CSDN博客 试过很多版本的在win10系统直接qemu安装arm版linux都失败了 也看
  • vm16安装windows系统

    安装win7系统 网上找到的iso均为ghost镜像 结果发现无法引导 找了个win10镜像可以引导 同时在创建一个cd加载win7的iso 进入win10的镜像PE 格式化硬盘 安装win7镜像 ok 同时 使用win7配置 安装win1
  • [创业之路-43] :复盘与自省 - 创业初感悟(冲动->纠结->忐忑)与“不贪、不赌、不悔”做人做事三原则的成形

    目录 创业冲动 冲动之后是纠结 选择后的忐忑 未来的应对之策 复盘后的体悟 做人做事三大基本原则1 不贪而心安 做人做事三大基本原则2 不赌而敬畏 做人做事三大基本原则3 不悔而未来 收获 创业冲动 虽然对创业进行了很多零散知识上的准备和多
  • 【WEB】关于网页设置 background-image: url死活显示不出来的解决办法

    图片或者背景显示不出来 大部分都是路径的问题 这是我图片所在的文件夹 相信很多有这个问题的小伙伴都是像我下面这样写的路径 那么背景图是不会显示出来的 解决办法如下图 原因是 在img的src中 是以当前html网页做相对文件 来设置引入图片
  • 全网最详细Postman接口测试使用教程(实战干G货)

    目录 导读 一 前言 二 接口测试 三 抓包 四 postman构造请求 五 其他的登录鉴权方式 六 总结 一 前言 测试行业现在越来越卷 不会点接口测试好像简历都已经拿不出手了 但很多小伙伴都会头疼 接口测试应该怎么入门 那么多的接口测试
  • vue axios三层封装

    utils文件下创建request js文件 第一层封装 引入axios文件 import axios from axios import qs from qs 声明公共的地址 axios defaults baseURL 设置超时 axi
  • 使用Python进行基于属性的测试

    When you write unit tests it s hard to find the right test cases You want to be certain that you covered all the interes
  • Acm Club 1326:算法2-8~2-11:链表的基本操作

    题目描述 链表是数据结构中一种最基本的数据结构 它是用链式存储结构实现的线性表 它较顺序表而言在插入和删除时不必移动其后的元素 现在给你一些整数 然后会频繁地插入和删除其中的某些元素 会在其中某些时候让你查找某个元素或者输出当前链表中所有的
  • 基于JT/T808协议、JT/T809协议、JT/T1078协议、苏标主动安全的车联网平台架构方案

    JT808是定位协议 通讯协议 基础协议 其他协议基于该协议进行扩展 JT809是转发协议 监管协议 第三方平台通过809向808进行数据获取与事件下发 JT1078是多媒体监控协议 视频 音频 对讲可以通过809扩展实现上级也可以多媒体监
  • Android 关于微信原生登录和友盟第三方微信登录来获取code那些坑(40029问题)

    如果你恰好集成了微信原生登录与友盟三方登录 那么可以继续往下看了 问题描述 本来在APP端使用openid就可以了的 结果未想到 后台要我们传一个Code过去 就是微信里面的Resp Error code这个 code 友盟登录里是直接获取
  • java 线程:概念与原理

    本文转载至 http lavasoft blog 51cto com 62575 99150 一 操作系统中线程和进程的概念 现在的操作系统是多任务操作系统 多线程是实现多任务的一种方式 进程是指一个内存中运行的应用程序 每个进程都有自己独
  • qt鼠标事件

    一 qt的鼠标事件包含头文件
  • 小程序 image标签 默认宽高问题,如何实现高度自适应

    微信小程序的图片image有默认的宽高 width 320px和height 240px 我遇到的业务场景是宽度100 高度自适应 所以 1 宽度设置成100 img width 100 2 设置mode属性 mode widthFix
  • 2019夏令营之行(下) 南大软件+北邮网研院

    夏令营 上 https blog csdn net Cc Sonia article details 95238001 正如上篇博客所说 北航计算机是我最满意的结果 所以剩下的这两个夏令营我就没认真参加2333 7 17 7 20 南大软件
  • 基于多进程并发-进程通讯之管道(pipe)

    一 管道 pipe 所谓的管道 就是内核 的 串缓存 Pipe 一个进程从管道的 端写 的数据 实际上是缓存在内核中的 另 端读取 也就是从内核中读取这段数据 特性 有两种类型的管道 匿名管道 有名管道 也叫命名管道 简单实现 有大小限制