To create a new process, we need to call CreateProcess().

 

Syntax:

  1. BOOL WINAPI CreateProcess(
  2. __in_opt LPCTSTR lpApplicationName,
  3. __inout_opt LPTSTR lpCommandLine,
  4. __in_opt LPSECURITY_ATTRIBUTES lpProcessAttributes,
  5. __in_opt LPSECURITY_ATTRIBUTES lpThreadAttributes,
  6. __in BOOL bInheritHandles,
  7. __in DWORD dwCreationFlags,
  8. __in_opt LPVOID lpEnvironment,
  9. __in_opt LPCTSTR lpCurrentDirectory,
  10. __in LPSTARTUPINFO lpStartupInfo,
  11. __out LPPROCESS_INFORMATION lpProcessInformation
  12. );

Parameters:

    1. lpApplicationName [in, optional] 
      The name of the module to be executed. 
      This module can be a Windows-based application. 
      It can be some other type of module (for example, MS-DOS or OS/2) if the appropriate subsystem is available on the local computer. 
      The string can specify the full path and file name of the module to execute or it can specify a partial name. In the case of a partial name, the function uses the current drive and current directory to complete the specification. The function will not use the search path. This parameter must include the file name extension; no default extension is assumed.
      The lpApplicationName parameter can be NULL.
      In that case, the module name must be the first white space delimited token in the lpCommandLine string.
    2. lpCommandLine [in, out, optional] 
      The command line to be executed. The maximum length of this string is 32,768 characters, including the Unicode terminating null character. If lpApplicationName is NULL, the module name portion of lpCommandLine is limited to MAX_PATH characters.
      The lpCommandLine parameter can be NULL. In that case, the function uses the string pointed to by lpApplicationName as the command line.
      If both lpApplicationName and lpCommandLine are non-NULL, the null-terminated string pointed to by lpApplicationName specifies the module to execute, and the null-terminated string pointed to by lpCommandLine specifies the command line. The new process can use GetCommandLine to retrieve the entire command line. Console processes written in C can use the argc and argv arguments to parse the command line. Because argv[0] is the module name, C programmers generally repeat the module name as the first token in the command line.
    1. lpProcessAttributes [in, optional] 
      A pointer to a SECURITY_ATTRIBUTES structure that determines whether the returned handle to the new process object can be inherited by child processes. If lpProcessAttributes is NULL, the handle cannot be inherited.
    1. lpThreadAttributes [in, optional] 
      A pointer to a SECURITY_ATTRIBUTES structure that determines whether the returned handle to the new thread object can be inherited by child processes. If lpThreadAttributes is NULL, the handle cannot be inherited. 
      The lpSecurityDescriptor member of the structure specifies a security descriptor for the main thread. If lpThreadAttributes is NULL o rlpSecurityDescriptor is NULL, the thread gets a default security descriptor. The ACLs in the default security descriptor for a thread come from the process token.
    1. bInheritHandles [in] 
      If this parameter TRUE, each inheritable handle in the calling process is inherited by the new process. If the parameter is FALSE, the handles are not inherited. Note that inherited handles have the same value and access rights as the original handles.
    1. dwCreationFlags [in] 
      The flags that control the priority class and the creation of the process. 
      This parameter also controls the new process's priority class, which is used to determine the scheduling priorities of the process's threads. 
      If none of the priority class flags is specified, the priority class defaults to NORMAL_PRIORITY_CLASS unless the priority class of the creating process is IDLE_PRIORITY_CLASSBELOW_NORMAL_PRIORITY_CLASS. In this case, the child process receives the default priority class of the calling process.
    1. lpEnvironment [in, optional] 
      A pointer to the environment block for the new process. If this parameter is NULL, the new process uses the environment of the calling process.
      An environment block consists of a null-terminated block of null-terminated strings. Each string is in the following form:

      1. name=value\0

      Because the equal sign is used as a separator, it must not be used in the name of an environment variable.
      An environment block can contain either Unicode or ANSI characters. 
      If the environment block pointed to by lpEnvironment contains Unicode characters, be sure that dwCreationFlags includes CREATE_UNICODE_ENVIRONMENT
      If this parameter is NULL and the environment block of the parent process contains Unicode characters, you must also ensure that dwCreationFlags includes CREATE_UNICODE_ENVIRONMENT.

    1. lpCurrentDirectory [in, optional] 
      The full path to the current directory for the process. The string can also specify a UNC path.
      If this parameter is NULL, the new process will have the same current drive and directory as the calling process. (This feature is provided primarily for shells that need to start an application and specify its initial drive and working directory.)
    1. lpStartupInfo [in] 
      A pointer to a STARTUPINFO or STARTUPINFOEX structure.
      To set extended attributes, use a STARTUPINFOEX structure and specify EXTENDED_STARTUPINFO_PRESENT in the dwCreationFlags parameter. Handles in STARTUPINFO must be closed with CloseHandle when they are no longer needed.
  1. lpProcessInformation [out] 
    A pointer to a PROCESS_INFORMATION structure that receives identification information about the new process. 
    Handles in PROCESS_INFORMATION must be closed with CloseHandle when they are no longer needed.

The following example shows the steps necessary to create a new process. If the application is started with a command-line parameter, the process will print this out and then create a child process without any parameters. If the process is started without any parameters, it prints out a message indicating this and exits.

  1. #include <Windows.h>
  2. #include <stdio.h>
  3.  
  4. int main(int argc, char* argv[])
  5. {
  6. STARTUPINFO startupInfo;
  7. PROCESS_INFORMATION processInfo;
  8.  
  9. if(argc > 1) {
  10. printf("Argument %s\n", argv[1]);
  11. printf("Starting child process\n");
  12.  
  13. memset(&startupInfo;, 0, sizeof(startupInfo));
  14. memset(&processInfo;, 0, sizeof(processInfo));
  15.  
  16. startupInfo.cb = sizeof(startupInfo);
  17.  
  18. if(CreateProcess(argv[0], 0, 0, 0, 0, 0, 0, 0,
  19. &startupInfo;, &processInfo;) == 0)
  20. {
  21. printf(" Error %d\n", GetLastError());
  22. }
  23. WaitForSingleObject(processInfo.hProcess, INFINITE);
  24. }
  25. else {
  26. printf("No argument\n");
  27. }
  28.  
  29. getchar();
  30.  
  31. return 0;
  32. }

Suppose the executable of the above code is MyProc.exe. If we type "MyProc.exe myArgument" into command line, the output we get is:

  1. Argument myArgument
  2. Starting child process
  3. No argument

The handle of the created process is returned in processInfo.hProcess. This handle is used to call WaitForSingleObject(). This call returns when the child process exits. The child process did not have any argument in the example, so the "No argument" was the output from the child process while the "Argument myArgument" was from the main process.

The following example is passing arguments to a child process. We need to repeat the application name as the first command-line parameter, "MyProc.exe myArgument". The entire command line gets passed to the child process.

  1. #include <Windows.h>
  2. #include <stdio.h>
  3.  
  4. int main(int argc, char* argv[])
  5. {
  6. STARTUPINFO startupInfo;
  7. PROCESS_INFORMATION processInfo;
  8.  
  9. if(argc == 1) {
  10. char Args[256];
  11. sprintf_s(Args, "dummyArgs %s", argv[0]);
  12. memset(&startupInfo;, 0, sizeof(startupInfo));
  13. memset(&processInfo;, 0, sizeof(processInfo));
  14.  
  15. startupInfo.cb = sizeof(startupInfo);
  16.  
  17. if(CreateProcess(argv[0], Args,
  18. 0, 0, 0, 0, 0, 0, &startupInfo;, &processInfo;) == 0)
  19. {
  20. printf(" Error %d\n", GetLastError());
  21. }
  22. WaitForSingleObject(processInfo.hProcess, INFINITE);
  23. }
  24. else {
  25. printf("Argument %s\n", argv[1]);
  26. }
  27.  
  28. getchar();
  29.  
  30. return 0;
  31. }

Output is:

  1. Argument myArgument
Memory Sharing Between Processes

Processes can share memory between them. Once one process has set up a region of memory with sharing attributes, another can open that region of memory and map it into its address space.

The file mapping function CreateFileMapping() is used by the shared memory. The parameter INVALID_HANDLE_VALUE is for creating a handle to a region of shared memory. This can then be mapped into the process by calling MapViewOfFile(). Except the fact that the function OpenFileMapping() is used to obtain the handle, the steps of attaching to an existing region of shared memory are similar.

An object can be shared between processes either by sharing the object's handle or by using a common name. The name can contain any character except a backslash and must start with either the local namespace identifier Local\ or the global namespace identifier Global\. The local namespace is private to each user while the global namespace is shared by all users.

The OpenFileMapping() call which opens an existing file mapping object takes three parameters:

  1. HANDLE WINAPI OpenFileMapping(
  2. __in DWORD dwDesiredAccess,
  3. __in BOOL bInheritHandle,
  4. __in LPCTSTR lpName );
  1. The first parameter gives the security attributes for the mapping object, which usually will be FILE_MAP_ALL_ACCESS to allow both reading and writing to the share memory.
  2. The second parameter is a boolean that determines whether the handle can be inherited by child processes.
  3. The third parameter is the name of the mapping object.

The CreateFileMapping() call creates the mapping object in the kernel, however, it does not actually map the object into user space. The call to MapViewOfFile() causes the shared object to be mapped into memory. The return value of this call is a pointer to the base address of the memory. This call takes file parameters:

  1. LPVOID WINAPI MapViewOfFile(
  2. __in HANDLE hFileMappingObject,
  3. __in DWORD dwDesiredAccess,
  4. __in DWORD dwFileOffsetHigh,
  5. __in DWORD dwFileOffsetLow,
  6. __in SIZE_T dwNumberOfBytesToMap );

Parameters:

    1. hFileMappingObject [in] 
      A handle to a file mapping object. The CreateFileMapping and OpenFileMappingfunctions return this handle.
    1. dwDesiredAccess [in] 
      The type of access to a file mapping object, which determines the protection of the pages. This parameter can be one of the following values.
    1. dwFileOffsetHigh [in] 
      A high-order DWORD of the file offset where the view begins.
    1. dwFileOffsetLow [in] 
      A low-order DWORD of the file offset where the view is to begin. The combination of the high and low offsets must specify an offset within the file mapping. They must also match the memory allocation granularity of the system. That is, the offset must be a multiple of the allocation granularity. To obtain the memory allocation granularity of the system, use the GetSystemInfo function, which fills in the members of a SYSTEM_INFO structure.
  1. dwNumberOfBytesToMap [in] 
    The number of bytes of a file mapping to map to the view. All bytes must be within the maximum size specified by CreateFileMapping . If this parameter is 0 (zero), the mapping extends from the specified offset to the end of the file mapping.

Once the process has finished with the shared memory, it needs to be unmapped by calling UnMapViewOfFile(), which takes the base address of the shared memory as a parameter:

  1. BOOL WINAPI UnmapViewOfFile(
  2. __in LPCVOID lpBaseAddress
  3. );

Then, the handle can be closed by calling CloseHandle().

The following example demonstrates how a region of memory can be created and then shared between two processes. If the application is started without any parameters, it will create a child process. The parent process will also create a region of shared memory and store a string into the shared memory. The shared memory is given the name sharedmemory:

  1. char ID[] = TEXT("Local\\sharedmemory");

It is created in the Local\ namespace. So, it is visible to all the processes owned by the user.

The child process attaches to the shared memory and can print out the value of the string stored there by the parent process. Once the child process has printed the string, it unmaps the memory and closes the file handle before exiting. Once the child process has exited, the parent process is free to unmap the memory, close the file handle, and then exit.

  1. #include <Windows.h>
  2. #include <stdio.h>
  3.  
  4. int main(int argc, char* argv[])
  5. {
  6. STARTUPINFO startupInfo;
  7. PROCESS_INFORMATION processInfo;
  8. HANDLE fileHandle;
  9. char ID[] = TEXT("Local\\sharedmemory");
  10. char *memory;
  11.  
  12. if(argc == 1) {
  13. fileHandle = CreateFileMapping(INVALID_HANDLE_VALUE,
  14. NULL, PAGE_READWRITE, 0, 1024, ID);
  15. memory = (char*)MapViewOfFile(fileHandle,
  16. FILE_MAP_ALL_ACCESS, 0, 0, 0);
  17. sprintf_s(memory, 1024, "%s", "Data from first process");
  18. printf("First process: %s\n", memory);
  19.  
  20. memset(&startupInfo;, 0, sizeof(startupInfo));
  21. memset(&processInfo;, 0, sizeof(processInfo));
  22. startupInfo.cb = sizeof(startupInfo);
  23.  
  24. char Args[256];
  25. sprintf_s(Args, "dummyArgs %s", argv[0]);
  26.  
  27. CreateProcess(argv[0], Args,
  28. 0, 0, 0, 0, 0, 0, &startupInfo;, &processInfo;);
  29. WaitForSingleObject(processInfo.hProcess, INFINITE);
  30.  
  31. UnmapViewOfFile(memory);
  32. CloseHandle(fileHandle);
  33. }
  34. else {
  35. fileHandle = OpenFileMapping(FILE_MAP_ALL_ACCESS, 0, ID);
  36. memory = (char*)MapViewOfFile(fileHandle,
  37. FILE_MAP_ALL_ACCESS, 0, 0, 0);
  38.  
  39. printf("Second process %s\n", memory);
  40.  
  41. UnmapViewOfFile(memory);
  42. CloseHandle(fileHandle);
  43. }
  44.  
  45. getchar();
  46.  
  47. return 0;
  48. }

The output we get:

  1. First process: Data from first process
  2. Second process Data from first process
Mutex Sharing Between Processes

To share a mutex between processes, we need to create mutex with a name. Then, other process can use the OpenMutex() or CreateMutex() to get a handle to the mutex. Here are the complexities involved in this:

  1. Only one process can create the mutex, and the others just open the existing mutex.
  2. The name should be unique.
  3. The name of the mutex should be passed to the other processes.

In the example below, the mutex is created by CteateMutex(). Here, we create two copies of the same processes and enables them to share a mutex.

  1. #include <Windows.h>
  2. #include <stdio.h>
  3.  
  4. int main(int argc, char* argv[])
  5. {
  6. STARTUPINFO startupInfo;
  7. PROCESS_INFORMATION processInfo;
  8. HANDLE sharedmutex;
  9.  
  10. ZeroMemory(&startupInfo;,sizeof(startupInfo));
  11. ZeroMemory(&processInfo;,sizeof(processInfo));
  12. startupInfo.cb = sizeof(startupInfo);
  13.  
  14. sharedmutex = CreateMutex(0,0,"MyMutex");
  15.  
  16. if(GetLastError() != ERROR_ALREADY_EXISTS)
  17. {
  18. if(CreateProcess(argv[0],0,0,0,0,0,0,0, &startupInfo;, &processInfo;) == 0) {
  19. printf("ERROR %d : Mutex already exists\n", GetLastError());
  20. }
  21.  
  22. WaitForInputIdle(processInfo.hProcess, INFINITE);
  23. }
  24.  
  25. WaitForSingleObject(processInfo.hProcess, INFINITE);
  26.  
  27. for(int i = 0; i <20; i++) {
  28. printf("Process %d Count %d\n", GetCurrentProcessId(),i);
  29. }
  30.  
  31. ReleaseMutex(sharedmutex);
  32. CloseHandle(sharedmutex);
  33.  
  34. getchar();
  35. return 0;
  36. }

Output is;

  1. ERROR 2 : Mutex already exists
  2. Process 6200 Count 0
  3. Process 6200 Count 1
  4. Process 6200 Count 2
  5. Process 6200 Count 3
  6. Process 6200 Count 4
  7. Process 6200 Count 5
  8. Process 6200 Count 6
  9. Process 6200 Count 7
  10. Process 6200 Count 8
  11. Process 6200 Count 9
  12. Process 6200 Count 10
  13. Process 6200 Count 11
  14. Process 6200 Count 12
  15. Process 6200 Count 13
  16. Process 6200 Count 14
  17. Process 6200 Count 15
  18. Process 6200 Count 16
  19. Process 6200 Count 17
  20. Process 6200 Count 18
  21. Process 6200 Count 19

If the mutex already exists, then a handle to the existing mutex is returned, and the error condition is set to ERROR_ALREADY_EXISTS. If this is not the error condition, then it is assumed by the code that this means that the mutex was created by the calling process, and the calling process needs to start a second copy. Note that the call to CreateMutex() takes the name of the mutex. The shared mutex is used to ensure that only one of the two processes counts up to 20 at a time. If there was no mutex, then both processes could be active simultaneously, and the console output would be a mix of the output from both processes. By using the mutex, the output is from just one of the processes at a time.

【转】Native Thread for Win32 C- Creating Processes(通俗易懂,非常好)的更多相关文章

  1. 【转】Native Thread for Win32 B-Threads Synchronization(通俗易懂,非常好)

    http://www.bogotobogo.com/cplusplus/multithreading_win32B.php   Synchronization Between Threads In t ...

  2. 【转】Native Thread for Win32 A- Create Thread(通俗易懂,非常好)

    http://www.bogotobogo.com/cplusplus/multithreading_win32A.php Microsoft Windows operating system's s ...

  3. JVM最多能创建多少个线程: unable to create new native thread

    转载自:http://www.rigongyizu.com/jvm-max-threads/ 有应用报出这样的异常“java.lang.OutOfMemoryError: unable to crea ...

  4. 记一次tomcat线程创建异常调优:unable to create new native thread

    测试在进行一次性能测试的时候发现并发300个请求时出现了下面的异常: HTTP Status 500 - Handler processing failed; nested exception is ...

  5. 解决Unable to create new native thread

    两种类型的Out of Memory java.lang.OutOfMemoryError: Java heap space error 当JVM尝试在堆中分配对象,堆中空间不足时抛出.一般通过设定J ...

  6. JVM截至多少线程可以创建: unable to create new native thread

    最近的测试需要很长的连接server.这些数据需要达到100W长连接,试client.一个线程来保持连接.查找linuxserver创建者默认3200当多个线程.这个错误将得到"java.l ...

  7. spark大批量读取Hbase时出现java.lang.OutOfMemoryError: unable to create new native thread

    这个问题我去网上搜索了一下,发现了很多的解决方案都是增加的nproc数量,即用户最大线程数的数量,但我修改了并没有解决问题,最终是通过修改hadoop集群的最大线程数解决问题的. 并且网络上的回答多数 ...

  8. JVM虚拟机宕机_java.lang.OutOfMemoryError: unable to create new native thread

    原因:当前用户的系统最最大程序数数已达到最大值,使用ulimit -u可以看到是1024   解决办法:在当前用户下使用ulimit -u 65535 然后再执行jsp,一切ok     功能说明:控 ...

  9. 剥下“java.lang.OutOfMemoryError: unable to create new native thread”的外衣 创建线程数公式(MaxProcessMemory - JVMMemory – ReservedOsMemory)

    剥下“java.lang.OutOfMemoryError: unable to create new native thread”的外衣 星期一早上到了公司,据称产品环境抛出了最可爱的异常—OutO ...

随机推荐

  1. Spring 基于Aspectj切面表达式

    package com.proc; import org.aspectj.lang.JoinPoint; import org.aspectj.lang.ProceedingJoinPoint; im ...

  2. CSS border 生成三角

    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xht ...

  3. 深层神经网络框架的python实现

    概述 本文demo非常适合入门AI与深度学习的同学,从最基础的知识讲起,只要有一点点的高等数学.统计学.矩阵的相关知识,相信大家完全可以看明白.程序的编写不借助任何第三方的深度学习库,从最底层写起. ...

  4. ubuntu 中安装redis

    1.apt-get install redis-server 2. 检查Redis服务器系统进程 ~ ps -aux|grep redis redis 4162 0.1 0.0 10676 1420 ...

  5. 破解Aspose 操作pdf word等文档 对10以下版本有效

    using System; using System.IO; namespace LicenseHelper { public static class License { public const ...

  6. Navicat Premium之MySQL客户端的下载、安装和使用(博主推荐)

    不多说,直接上干货! 前期工作 若需使用Navicat Premium,则需要先安装MySQL,在此就不叙述了.具体可见我的博客: MySQL Server类型之MySQL客户端工具的下载.安装和使用 ...

  7. 区别getElementByID,getElementsByName,getElementsByTagName

    以人来举例说明,人有能标识身份的身份证,有姓名,有类别(大人.小孩.老人)等. 1. ID 是一个人的身份证号码,是唯一的.所以通过getElementById获取的是指定的一个人. 2. Name ...

  8. OpenCV2马拉松第24圈——轮廓提取

    计算机视觉讨论群162501053 转载请注明:http://blog.csdn.net/abcd1992719g/article/details/27979267 收入囊中 在图片中找到轮廓而且描绘 ...

  9. 安卓-启动下一个Activity

    Intent intent = new Intent(NotebookActivity.this, MessageActivity.class); startActivity(intent); 通过意 ...

  10. Google 商店:您的应用静态链接到的 OpenSSL 版本有多个安全漏洞。建议您尽快更新 OpenSSL

    安全提醒 您的应用静态链接到的 OpenSSL 版本有多个安全漏洞.建议您尽快更新 OpenSSL. 在开头为 1.0.1h.1.0.0m和 0.9.8za的 OpenSSL 版本中这些漏洞已得到修复 ...