个人知识库 个人知识库
首页
关于
  • C语言
  • CPlusPlus
  • Linux
  • PHP
  • Nginx
  • MySQL
  • Redis
  • Docker
  • Kubernetes
  • SRS
阅读
常用工具
  • 分类
  • 标签
  • 归档
GitHub

Agnes001

坚持是一件很伟大的事业
首页
关于
  • C语言
  • CPlusPlus
  • Linux
  • PHP
  • Nginx
  • MySQL
  • Redis
  • Docker
  • Kubernetes
  • SRS
阅读
常用工具
  • 分类
  • 标签
  • 归档
GitHub
  • C语言

  • CPlusPlus

    • 基础特性

      • 枚举
      • 字符指针
    • vs2019设置
    • C++11特性

    • 并发编程

    • 引用
    • 类和对象
    • 友元和运算符重载
    • 继承
    • 继承和多态
    • 模板
    • C++基础总结
    • 类型转换
    • 异常
    • 容器
    • 算法
    • C++程序设计
    • C++ Primer总结
    • 编程技巧
    • 标准库体系结构与内核分析
    • 设计模式
    • cmake配置C++工程
    • libcurl的使用总结
    • web开发框架--drogon
    • log4cplus使用
    • C++数据类型
    • 函数
    • 线程
    • 进程
      • 进程的概念
      • 创建进程 CreateProcess 函数
      • 进程间的通信方式
        • 剪切板
        • WM_COPYDATA
        • 油槽
        • 匿名管道
        • 命名管道
    • 文件操作
    • 日常问题记录
    • Cpp案例程序
    • 多线程
    • 侯捷c++11新特性
    • 侯捷stl
  • Lua技术栈

  • edoyun

  • 内存管理

  • 数据结构

  • 网络编程

  • Linux

  • 池化技术

  • 操作系统

  • python

  • 编程技术
  • CPlusPlus
Agnes001
2021-01-25

进程

# 进程的概念

进程是资源申请,高度和独立运行的单位,因此,它使用系统中的运行资源,而程序不能申请系统资源,不能被系统调度也不能作为独立运行的单位,因此它不占系统运行资源.
进程组成:
<1> 操作系统用来管理进行的内核对象
内核对象也是系统用来存放关于进程的统计信息的地方.内核对象是操作系统内部分配的一个内存块,该内存块是一种数据结构,其成员负责维护该对象的各种信息.
<2> 地址空间
它包含所有可执行模块或 DLL 模块的代码和数据.另外,它也包含动态内存分配的空间,例如线程的栈和堆分配空间
进程从来不执行任何东西,它只是纯种的容器,若要使进程完成某项操作,它必须拥有一个在它的环境中运行的纯种,此线程负责执行包含在进程的地址空间的中的代码.也就是,真正完成代码执行的是线程,而进程只是纯种的容器, 或者说是线程的执行环境。

# 创建进程 CreateProcess 函数

 CreateProcessW( 
    _In_opt_ LPCWSTR lpApplicationName,// 该字符串可以指定要执行的模块的完整路径 和文件名 
    _Inout_opt_ LPWSTR lpCommandLine, //命令行 
    _In_opt_ LPSECURITY_ATTRIBUTES lpProcessAttributes, //该 结构确定子进程是否可以继承返回到新进程对象的句柄。如果 lpProcessAttributes为NULL,则不能继承该句柄 
    _In_opt_ LPSECURITY_ATTRIBUTES lpThreadAttributes, //该 结构确定子进程是否可以继承返回到新线程对象的句柄。如果 lpThreadAttributes为NULL,则不能继承该句柄 
    _In_ BOOL bInheritHandles, //如果此参数为TRUE,则新进程将继承调用进程中的每个可继承句柄。如果参数为FALSE,则不会继承句柄。请注意,继承的句柄与原始句柄具有相同的值和访问权限 
    _In_ DWORD dwCreationFlags,// 控制优先级类别和流程创建的标志 CREATE_NEW_CONSOLE 
    _In_opt_ LPVOID lpEnvironment,// 指向新进程的环境块的指针。如果此参数为NULL,则新进程将使用调用进程的环境 
    _In_opt_ LPCWSTR lpCurrentDirectory,// 进程当前目录的完整路径 
    _In_ LPSTARTUPINFOW lpStartupInfo, //设置扩展属性 
    _Out_ LPPROCESS_INFORMATION lpProcessInformation // 该结构接收有关新进程的标识信息
);
//创建一个用谷歌浏览器打开百度 
#include <windows.h> 
#include <stdio.h> 
#include <tchar.h> 
void RunExe() 
{ 
    STARTUPINFO strStartupInfo; 
    memset(&strStartupInfo, 0, sizeof(strStartupInfo)); 
    strStartupInfo.cb = sizeof(strStartupInfo); 
    PROCESS_INFORMATION szProcessInformation; 
    memset(&szProcessInformation, 0, sizeof(szProcessInformation)); 
    TCHAR szCommandLine[] =_T("\"D:\\Program Files (x86)\\ChromeCore\\ChromeCore.exe\" http://www.baidu.com/"); 
    int iRet = CreateProcess( NULL, szCommandLine, NULL, NULL, false, CREATE_NEW_CONSOLE, NULL, NULL, &strStartupInfo, &szProcessInformation ); 
    if (iRet) 
    { 
        //创建成功 
        printf_s("Create Success iRet = %d\n", iRet); 
        WaitForSingleObject(szProcessInformation.hProcess, 3000); 
        //close进程计数减一,进程结束后,进程计数再减一
        CloseHandle(szProcessInformation.hProcess); 
        CloseHandle(szProcessInformation.hThread); 
        szProcessInformation.dwProcessId = 0; 
        szProcessInformation.dwThreadId = 0; 
        szProcessInformation.hThread = NULL; 
        szProcessInformation.hProcess = NULL; 
    }
    else 
    { 
        printf_s("Create Success iRet = %d\n", iRet); 
        printf_s("errorcode = %d\n", GetLastError()); 
    } 
}
int main() 
{
    printf("This is Bingo\n"); 
    RunExe(); 
    system("pause"); 
    return 0; 
}

# 进程间的通信方式

# 剪切板

void CClipboardDlg::OnBnClickedSendBtn() 
{
    // 1 打开剪切板 
    if (OpenClipboard()) 
    { 
        //2 清空剪切板 
        EmptyClipboard(); 
        char* szSendBuf; 
        //3 获取编辑框的内容 
        CStringW strSendW; 
        GetDlgItemText(IDC_EDIT_SEND, strSendW); 
        CStringA strSend = (CStringA)strSendW; 
        //4 分配一个内存对象,内存对象的句柄就是hClip 
        HANDLE hClip = GlobalAlloc(GMEM_MOVEABLE, strSend.GetLength() + 1); 
        //5 将剪切板句柄加锁 
        szSendBuf = (char*)GlobalLock(hClip); 
        strcpy(szSendBuf, strSend); 
        TRACE("szSendBuf = %s", szSendBuf); 
        GlobalUnlock(hClip); 
        //6 将数据放入剪切板 
        SetClipboardData(CF_TEXT, hClip); 
        //7 关闭剪切板 
        CloseClipboard(); 
    } 
}
void CClipboardDlg::OnBnClickedRecvBtn() 
{
    if (OpenClipboard()) 
    { 
        //确认剪切板是否可用 
        if (IsClipboardFormatAvailable(CF_TEXT)) 
        { 
            HANDLE hClip; 
            char* pBuf; 
            //向剪切板要数据 
            hClip = GetClipboardData(CF_TEXT); 
            pBuf = (char*)GlobalLock(hClip);
            USES_CONVERSION; 
            LPCWSTR strBuf = A2W(pBuf); 
            GlobalUnlock(hClip); 
            SetDlgItemText(IDC_EDIT_RECV, strBuf); 
        }
        CloseClipboard(); 
    } 
}

# WM_COPYDATA

WM_COPYDATA wParam传递数据的窗口的句柄。
指向 COPYDATASTRUCT 结构的指针,该结构包含要传递的数据。 如果接收方应用程序处理此消息,则应返回 TRUE;否则,应返回 FALSE。

//发送端 
void CWMCOPYDATASENDDlg::OnBnClickedSend() 
{ 
    // 必须要知道标题 句柄 
    CString strWindowTitle = _T("MFCRecv"); 
    CString strDataToSend = _T("Hello ,this is Bingo WM_COPYDATA"); 
    // 利用标题句柄 
    HWND hRecvWnd = ::FindWindow(NULL, strWindowTitle.GetBuffer(0)); 
    if (hRecvWnd != NULL && ::IsWindow(hRecvWnd))
    { 
        //数据的封装 
        COPYDATASTRUCT cpd; 
        cpd.dwData = 0; 
        cpd.cbData = strDataToSend.GetLength() * sizeof(TCHAR); 
        cpd.lpData = (PVOID)strDataToSend.GetBuffer(0); ::SendMessage(hRecvWnd, WM_COPYDATA, (WPARAM)(AfxGetApp()- >m_pMainWnd),(LPARAM)&cpd); 
    }
    strDataToSend.ReleaseBuffer();
}

接收端,界面上右击,点击类向导,消息-WM_COPYDATA,双击,转到其消息响应的函数中

BOOL CWMCOPYDATADlg::OnCopyData(CWnd* pWnd, COPYDATASTRUCT* pCopyDataStruct) 
{ 
    //消息响应函数 
    //解析数据 
    LPCTSTR szText = (LPCTSTR)(pCopyDataStruct->lpData); 
    DWORD dwLength = (DWORD)pCopyDataStruct->cbData; 
    TCHAR szRecvText[1024] = { 0 }; 
    memcpy(szRecvText, szText, dwLength); 
    MessageBox(szRecvText, _T("Bingo"), MB_OK); 
    return CDialogEx::OnCopyData(pWnd, pCopyDataStruct); 
}

# 油槽

使用邮槽通信的进程分为服务端和客户端。邮槽由服务端创建,在创建时需要指定邮槽名,创建后服务端得到邮槽的句柄。在邮槽创建后,客户端可以通过邮槽名打开邮槽, 在获得句柄后可以向邮槽写入消息。
邮槽通信是单向的,只有服务端才能从邮槽中读取消息,客户端只能写入消息。消息是先入先出的。客户端先写入的消息在服务端先被读取。
通过邮槽通信的数据可以是任意格式的,但是一条消息不能大于 424 字节。
邮槽除了在本机内进行进程间通信外,在主机间也可以通信。但是在主机间进行邮槽通信,数据通过网络传播时使用的是数据报协议(UDP),所以是一种不可靠的通信。通过网络进行邮槽通信时,客户端必须知道服务端的主机名或域名。

// 服务端
void CChildView::OnSlot() { 
    // "\\\\.\\mailslot\\Mymailslot \\.\mailslot\Mymailslot 
    // 1 创建一个邮槽 
    LPCTSTR szSlotName = TEXT("\\\\.\\mailslot\\Mymailslot");
    HANDLE hSlot = CreateMailslot(szSlotName, 
    0, // no maximum message size 
    MAILSLOT_WAIT_FOREVER, // no time-out for operations NULL
    ); // default security 
    if (hSlot == INVALID_HANDLE_VALUE) 
    {
        TRACE("CreateMailslot failed with %d\n", GetLastError()); 
        return ; 
    }
    // 2 读取数据 
    char szBuf[100] = { 0 }; 
    DWORD dwRead; 
    TRACE("Begin ReadFile"); 
    if (!ReadFile(hSlot, szBuf, 100, &dwRead, NULL)) 
    { 
        MessageBox(_T("读取数据失败")); 
        CloseHandle(hSlot); 
        return; 
    }
    TRACE("End ReadFile"); 
    MessageBox((CStringW)szBuf); 
    CloseHandle(hSlot); 
}
// 客户端
void CChildView::OnSend() 
{
    // 创建一个文件句柄 
    LPCTSTR szSlotName = TEXT("\\\\.\\mailslot\\Mymailslot"); 
    HANDLE hMailSlot = CreateFile(szSlotName, FILE_GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL,NULL 
    ); 
    if (hMailSlot == INVALID_HANDLE_VALUE) 
    { 
        TRACE("CreateFile failed with %d\n", GetLastError()); 
        return; 
    }
    //写入数据 
    char szBuf[] = "Bingo is handsome"; 
    DWORD dwWrite; 
    if (!WriteFile(hMailSlot, szBuf, strlen(szBuf) + 1, &dwWrite, NULL)) 
    { 
        MessageBox(_T("写入数据失败")); C
        loseHandle(hMailSlot);
        return; 
    }
    CloseHandle(hMailSlot); 
}

# 匿名管道

匿名管道是一个没有命名的单向管道,本质上就是一个共享的内存区域。通常用来在父进程和子进程之间通信。只能实现本地两个进程之间的通信。不能实现网络通信。

CreatePipe( 
    
    _Out_ PHANDLE hReadPipe, //该变量接收管道的读取句柄 
    _Out_ PHANDLE hWritePipe,// 该变量接收管道的写句柄 
    _In_opt_ LPSECURITY_ATTRIBUTES lpPipeAttributes,//NULL 
    _In_ DWORD nSize //管道缓冲区的大小 0 :默认缓冲区大小 
);
// 父进程
HANDLE hReadPipe;
HANDLE hWritePipe;
// 创建子进程
void CChildView::OnPipeCreate() 
{ 
    // TODO: 在此添加命令处理程序代码 
    //创建匿名管道 
    SECURITY_ATTRIBUTES sa; 
    sa.bInheritHandle = TRUE; 
    sa.lpSecurityDescriptor = NULL; 
    sa.nLength = sizeof(SECURITY_ATTRIBUTES); 
    if (!CreatePipe(&hReadPipe, &hWritePipe, &sa, 0)) 
    { 
        MessageBox(_T("匿名管道创建失败")); 
        return; 
    }
    //创建子进程 
    STARTUPINFO strStartupInfo; //用来指定新进程窗口如何显示 
    memset(&strStartupInfo, 0, sizeof(strStartupInfo)); 
    strStartupInfo.cb = sizeof(strStartupInfo); 
    strStartupInfo.dwFlags = STARTF_USESTDHANDLES; 
    strStartupInfo.hStdInput = hReadPipe; 
    strStartupInfo.hStdOutput = hWritePipe; 
    strStartupInfo.hStdError = GetStdHandle(STD_ERROR_HANDLE); 

    PROCESS_INFORMATION szProcessInformation;
    memset(&szProcessInformation, 0, sizeof(szProcessInformation)); 
    int iRet = CreateProcess( _T("MailSlotClient.exe"), NULL, NULL, NULL, TRUE, 0,NULL, NULL, &strStartupInfo, &szProcessInformation );
    if (iRet) 
    { 
        //创建成功 
        CloseHandle(szProcessInformation.hProcess); 
        CloseHandle(szProcessInformation.hThread); 
        szProcessInformation.dwProcessId = 0; 
        szProcessInformation.dwThreadId = 0; 
        szProcessInformation.hThread = NULL; 
        szProcessInformation.hProcess = NULL; 
    }
    else 
    {
        CloseHandle(hReadPipe); 
        CloseHandle(hWritePipe); 
        hReadPipe = NULL; 
        hWritePipe = NULL; 
        MessageBox(_T("创建子进程失败")); 
        return; 
    } 
}

void CChildView::OnPipeRead() 
{ 
    char szBuf[100] = { 0 }; 
    DWORD dwRead; 
    TRACE("Begin ReadFile"); 
    if (!ReadFile(hReadPipe, szBuf, 100, &dwRead, NULL)) 
    { 
        MessageBox(_T("读取数据失败")); 
        return; 
    }
    TRACE("End PipeReadFile"); 
    MessageBox((CStringW)szBuf);
}
void CChildView::OnPipeWrite() 
{
    //写入数据 
    char szBuf[] = "Bingo hen shuai"; 
    DWORD dwWrite; 
    if (!WriteFile(hWritePipe, szBuf, strlen(szBuf) + 1, &dwWrite, NULL)) 
    { 
        MessageBox(_T("写入数据失败")); 
        return; 
    } 
}
// 子进程
hReadCliPipe =GetStdHandle(STD_INPUT_HANDLE); 
hWriteCliPipe = GetStdHandle(STD_OUTPUT_HANDLE); 
void CChildView::OnCliPipeRead() 
{ 
    char szBuf[100] = { 0 }; 
    DWORD dwRead; 
    TRACE("Begin ReadFile"); 
    //查找所有引用shift + alt + F 
    if (!ReadFile(hReadCliPipe, szBuf, 100, &dwRead, NULL)) 
    { 
        MessageBox(_T("读取数据失败")); 
        return; 
    }
    TRACE("End PipeReadFile"); 
    MessageBox((CStringW)szBuf);
}

void CChildView::OnCliPipeWrite() 
{ 
    char szBuf[] = "Bingo Bingo"; 
    DWORD dwWrite; 
    if (!WriteFile(hWriteCliPipe, szBuf, strlen(szBuf) + 1, &dwWrite, NULL)) 
    { 
        MessageBox(_T("写入数据失败")); 
        CloseHandle(hWriteCliPipe); 
        return; 
    }
    CloseHandle(hWriteCliPipe); 
}

# 命名管道

与Socket相似,支持网络之间不同进程的通信

CreateNamedPipe 
HANDLE CreateNamedPipeA( 
    LPCSTR lpName, // \.\pipe<i>pipename 
    DWORD dwOpenMode, 
    DWORD dwPipeMode, 
    DWORD nMaxInstances, 
    DWORD nOutBufferSize, 
    DWORD nInBufferSize,
    DWORD nDefaultTimeOut, 
    LPSECURITY_ATTRIBUTES lpSecurityAttributes 
);
等待连接 
BOOL ConnectNamedPipe( 
    HANDLE hNamedPipe, 
    LPOVERLAPPED lpOverlapped 
);

WaitNamedPipe(szNamedPipeName, NMPWAIT_WAIT_FOREVER)
HANDLE hNamedPipe;
// 服务端
void CChildView::OnCreateNamedPipe() 
{ 
    //1 创建一个命名管道 
    LPCTSTR szPipeName = TEXT("\\\\.\\pipe\\mypipe"); 
    hNamedPipe = CreateNamedPipe(szPipeName,PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED, PIPE_TYPE_BYTE, 1, 1024, 1024, 0, NULL); 
    if (hNamedPipe == INVALID_HANDLE_VALUE) 
    { 
        TRACE("CreateNamedhPipe failed with %d\n", GetLastError()); 
        MessageBox(_T("创建命名管道失败")); 
        return; 
    }
    // 2 等待客户端的连接 
    HANDLE hEvent = CreateEvent(NULL, TRUE, FALSE, NULL); 
    if (NULL == hEvent) 
    { 
        MessageBox(_T("创建事件失败")); 
        CloseHandle(hNamedPipe); hNamedPipe = NULL; 
        return; 
    }
    OVERLAPPED ovlap; 
    ZeroMemory(&ovlap, sizeof(OVERLAPPED)); 
    ovlap.hEvent = hEvent; 
    //等待连接 
    if (!ConnectNamedPipe(hNamedPipe, &ovlap)) 
    { 
        if (ERROR_IO_PENDING != GetLastError()) 
        { 
            MessageBox(_T("等待客户端连接失败")); 
            CloseHandle(hNamedPipe); 
            CloseHandle(hEvent); 
            hNamedPipe = NULL; 
            hEvent = NULL; 
            return; 
        } 
    }
    if (WaitForSingleObject(hEvent,INFINITE) == WAIT_FAILED) 
    { 
        MessageBox(_T("等待对象失败")); 
        CloseHandle(hNamedPipe); 
        CloseHandle(hEvent); 
        hNamedPipe = NULL; 
        hEvent = NULL; return; 
    }
}

void CChildView::OnSreadNamedPipe() 
{ 
    char szBuf[100] = { 0 }; 
    DWORD dwRead; 
    if (!ReadFile(hNamedPipe, szBuf, 100, &dwRead, NULL)) 
    { 
        MessageBox(_T("读取数据失败")); 
        return; 
    }
    MessageBox((CStringW)szBuf); 
}

void CChildView::OnSwriteNamedpipe() 
{ 
    //写入数据 
    char szBuf[] = "OnNamedPipe Server"; 
    DWORD dwWrite; 
    if (!WriteFile(hNamedPipe, szBuf, strlen(szBuf) + 1, &dwWrite, NULL)) 
    { 
        MessageBox(_T("写入数据失败")); 
        return; 
    }
}
// 客户端 连接命名管道
void CChildView::OnConnectNamedPipe() 
{ 
    LPCTSTR szNamedPipeName = TEXT("\\\\.\\pipe\\mypipe"); 
    if (0 == WaitNamedPipe(szNamedPipeName, NMPWAIT_WAIT_FOREVER)) 
    { 
        MessageBox(_T("当前没有可以利用的管道")); 
        return; 
    }
    hNamedPipe = CreateFile(szNamedPipeName, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); 
    if (hNamedPipe == INVALID_HANDLE_VALUE) 
    { 
        TRACE("CreateFile failed with %d\n",
        GetLastError()); 
        MessageBox(_T("打开命名管道失败!")); 
        hNamedPipe = NULL; 
        return; 
    } 
}

void CChildView::OnReadNamedPipe() 
{ 
    char szBuf[100] = { 0 }; 
    DWORD dwRead; 
    if (!ReadFile(hNamedPipe, szBuf, 100, &dwRead, NULL)) 
    { 
        MessageBox(_T("读取数据失败")); 
        return; 
    }
    MessageBox((CStringW)szBuf); 
}

void CChildView::OnWriteNamedPipe() 
{ 
    char szBuf[] = "NAMEDPIPE CLIENT"; 
    DWORD dwWrite; 
    if (!WriteFile(hNamedPipe, szBuf, strlen(szBuf) + 1, &dwWrite, NULL)) 
    { 
        MessageBox(_T("写入数据失败")); 
        CloseHandle(hWriteCliPipe); 
        return; 
    }
    CloseHandle(hWriteCliPipe); 
}
编辑此页
#Cpp #process
线程
文件操作

← 线程 文件操作 →

Theme by Vdoing
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式