windows进程和线程

Windows进程

进程是一个容器,包含程序执行需要的代码、数据、资源等等信息。Windows是多任务操作系统,可以同时执行多个进程。

  • Windows进程的特点:
    • 每个进程都有自己的ID号
    • 每个进程都有自己的地址空间,进程之间无法访问对方的地址空间。
    • 每个进程都有自己的安全属性
    • 每个进程当中至少包含一个线程
  • 进程环境信息(进程上下文)
    • 获取和释放环境信息
      • 获取
        LPVOID GetEnvironmentStrings(VOID);
      • 释放
      BOOL FreeEnvironmentStrings(
        LPTSTR lpszEnvironmentBlock  
         // environment strings
      );
    • 获取和设置环境变量
      GetEnvironmentVariable
      SetEnvironmentVariable
  • 进程的信息
    1 进程ID
    GetCurrentProcessId
    2 进程句柄
    GetCurrentProcess返回进程的伪句柄(-1),可以使用该句柄访问该进程的所有操作。
  • 进程的使用
    1. 创建进程
      WinExec - 早期16位
      ShellExecute - Shell操作
      CreateProcess - 目前最多使用
    BOOL CreateProcess(
        LPCTSTR lpApplicationName,//应用程序名称
        LPTSTR lpCommandLine, //命令行参数
        LPSECURITY_ATTRIBUTES lpProcessAttributes, //进程安全属性 SD
        LPSECURITY_ATTRIBUTES lpThreadAttributes,
        //线程安全属性 SD
        BOOL bInheritHandles, //进程的句柄继承
        DWORD dwCreationFlags, //创建方式
        LPVOID lpEnvironment, //环境信息
        LPCTSTR lpCurrentDirectory,//当前目录
        LPSTARTUPINFO lpStartupInfo, //起始信息
        LPPROCESS_INFORMATION lpProcessInformation 
        //返回进程和线程的句柄ID
    );
    1. 结束进程
    VOID ExitProcess(
        UINT uExitCode   // exit code for all threads
    );  
    BOOL TerminateProcess(
         HANDLE hProcess, // handle to the process
         UINT uExitCode   // exit code for the process
    );
    1. 通过进程ID获取 进程句柄
    HANDLE OpenProcess(
        DWORD dwDesiredAccess,  //访问权限
        BOOL bInheritHandle,    //继承标识
        DWORD dwProcessId       //进程ID
    ); 返回进程句柄
    1. 关闭进程句柄
      CloseHandle
    2. 进程间的等候
      等候 可等候的句柄 的信号
      DWORD WaitForSingleObject(
      HANDLE hHandle, //句柄
      DWORD dwMilliseconds //等候时间 INFINITE
      );
      阻塞函数,等候句柄的信号,只在句柄有信号或超出等候时间,才会结束等候。
Windows线程

Windows线程是可以执行的代码的实例。系统是以线程为单位调度程序。一个程序当中可以有多个线程,实现多任务的处理。

  • Windows线程的特点:
    • 线程都具有1个ID
    • 线程具有自己的安全属性
    • 每个线程都具有自己的内存栈
    • 每个线程都具有自己的寄存器信息
  • 进程多任务和线程多任务:
    • 进程多任务是每个进程都使用私有地址空间,
    • 线程多任务是进程内的多个线程使用同一个地址空间。
  • 线程的调度:
    将CPU的执行时间划分成时间片,依次根据时间片执行不同的线程。
    线程轮询:线程A -> 线程B -> 线程A......

  • 线程的使用
  1. 定义线程处理函数
    DWORD WINAPI ThreadProc( LPVOID lpParameter //创建线程时,传递给线程的参数 );
  2. 创建线程
    HANDLE CreateThread( LPSECURITY_ATTRIBUTES lpThreadAttributes,//安全属性 SIZE_T dwStackSize, //线程栈的大小 LPTHREAD_START_ROUTINE lpStartAddress, //线程处理函数的函数地址 LPVOID lpParameter, //传递给线程处理函数的参数 DWORD dwCreationFlags,//线程的创建方式, LPDWORD lpThreadId //创建成功,返回线程的ID ); 创建成功,返回线程句柄
    dwCreationFlags:
    0 - 创建之后线程立刻执行
    CREATE_SUSPENDED - 创建之后线程处于挂起状态。
  3. 结束线程
    • 结束指定线程
    BOOL TerminateThread(
        HANDLE hThread,    // handle to thread
        DWORD dwExitCode   // exit code
    );
    • 结束函数所在的线程
    VOID ExitThread(
        DWORD dwExitCode   // exit code for this thread
    );
  4. 关闭线程句柄
    CloseHandle
  5. 线程的挂起和执行
    • 挂起
    DWORD SuspendThread(
         HANDLE hThread   // handle to thread
    );
     * 执行
    DWORD ResumeThread(
        HANDLE hThread   // handle to thread
    );
  6. 线程的信息
    GetCurrentThreadId - 获取当前线程的ID
    GetCurrentThread - 获取当前线程的句柄
    打开指定ID的线程,获取其句柄
    HANDLE OpenThread( DWORD dwDesiredAccess, // access right BOOL bInheritHandle, // handle inheritance option DWORD dwThreadId // thread identifier );
多线程的问题

线程A -> 线程B -> 线程A 。。。。。

当线程A执行printf输出时,如果线程A的执行时间结束,系统会将线程A的相关信息(栈、寄存器)压栈保护,同时将线程B相关信息恢复,然后执行线程B,线程B继续输出字符。由于线程A正输出字符,线程B会继续输出,画面字符会产生混乱。

  • 线程同步技术
    • 原子锁
      • 原子锁概念
        相关问题
        多个线程对同一个数据进行原子操作,会产生结果
        丢失。比如执行++运算时,
        当线程A执行g_nValue++时,如果线程切换时间
        正好是在线程A将值保存到g_nValue之前,
        线程B继续执行g_nValue++,那么当线程A再次被切换回来之后,会将原来线程A保存的值保存到g_nValue上,线程B进行的加法操作被覆盖。
      • 原子锁的使用
        原子锁-对单条指令的操作。
        API
        InterlockedIncrement
        InterlockedDecrement
        InterlockedCompareExchange
        InterlockedExchange
        ...
        原子锁的实现:
        直接对数据所在的内存操作,并且在任何一个瞬间只能有一个线程访问。
    • 临界区(段)
      相关问题
      printf输出混乱,多线程情况下同时使用一段代码。
      临界区可以锁定一段代码,防止多个线程同时使用该段代码
      使用
      1. 初始化一个临界区
      VOID InitializeCriticalSection(
      LPCRITICAL_SECTION lpCriticalSection  
      //临界区变量
      );
      1. 进入临界区
        添加到被锁定的代码之前
      VOID EnterCriticalSection(
      LPCRITICAL_SECTION lpCriticalSection  // critical section
      );
      1. 离开临界区
        添加到被锁定的代码之后
      VOID LeaveCriticalSection(
      LPCRITICAL_SECTION lpCriticalSection   // critical section
      );
      1. 删除临近区
      VOID DeleteCriticalSection(
      LPCRITICAL_SECTION lpCriticalSection   
      //临界区变量
      );
      • 原子锁和临界区
        原子锁 - 单条指令。
        临界区 - 单条或多行代码。
    • 互斥 Mutex
      相关的问题
      多线程下代码或资源的共享使用。
      • 互斥的使用
      1. 创建互斥
      HANDLE CreateMutex(
       LPSECURITY_ATTRIBUTES lpMutexAttributes,
         //安全属性
      BOOL bInitialOwner,//初始的拥有者
       LPCTSTR lpName    //命名
      ); 创建成功返回互斥句柄
        * bInitialOwner - 初始的拥有者
            * TRUE  - 调用CreateMutex的线程拥有互斥
            * FALSE - 创建的时没有线程拥有互斥
      1. 等候互斥
        WaitFor....
        互斥的等候遵循谁先等候谁先获取。
      2. 释放互斥
        BOOL ReleaseMutex(
        HANDLE hMutex // handle to mutex
        );
      3. 关闭互斥句柄
        CloseHandle
      • 互斥和临界区的区别

        • 临界区 - 用户态,执行效率高,只能在同一个进程中使用。
        • 互斥 - 内核态,执行效率低,可以通过命名的方式跨进程使用。
    • 事件
      相关问题
      程序之间的通知的问题。
      事件的使用
      1. 创建事件
      HANDLE CreateEvent(
      LPSECURITY_ATTRIBUTES lpEventAttributes, //安全属性
      BOOL bManualReset,                       
              //事件复位方式,TRUE手动,FALSE自动
      BOOL bInitialState,       //事件初始状态,TRUE有信号
      LPCTSTR lpName  //事件命名
      ); 创建成功返回 事件句柄
      1. 等候事件
        WaitForSingleObject/
        WaitForMultipleObjects
      2. 触发事件
        • 将事件设置成有信号状态
        BOOL SetEvent(
        HANDLE hEvent   // handle to event
        );
        • 将事件设置成无信号状态
        BOOL ResetEvent(
        HANDLE hEvent   // handle to event
        );
      3. 关闭事件 CloseHandle

      小心事件的死锁。

    • 信号量
      相关的问题
      类似于事件,解决通知的相关问题。但是可以提供一个计数器,可以设置次数。
      信号量的使用
      1. 创建 信号量
      HANDLE CreateSemaphore(
      LPSECURITY_ATTRIBUTES lpSemaphoreAttributes, 
      //安全属性
      LONG lInitialCount,        //初始化信号量数量   
      LONG lMaximumCount, //信号量的最大值
      LPCTSTR lpName           //命名
      ); 创建成功返回信号量句柄
      1. 等候信号量
        WaitFor...
        每等候通过一次,信号量的信号减1,直到为0阻塞
      2. 释放信号量(重新给信号量设置计数值)
      BOOL ReleaseSemaphore(
      HANDLE hSemaphore, //信号量句柄
      LONG lReleaseCount, //释放数量
      LPLONG lpPreviousCount   
      //释放前原来信号量的数量,可以为NULL
      );
      1. 关闭句柄
        CloseHandle

    可等候定时器

    • 等候函数
      • WaitForSingleObject - 等候单个
      • WaitForMultipleObjects - 等候多个
      DWORD WaitForMultipleObjects(
        DWORD nCount, //句柄数量
        CONST HANDLE *lpHandles,  //句柄BUFF的地址
        BOOL bWaitAll,//等候方式
        DWORD dwMilliseconds      // 等候时间 INFINITE
      );
      • bWaitAll - 等候方式
        TRUE - 表示所有句柄都有信号,才结束等候
        FASLE- 表示句柄中只要有1个有信号,就结束等候。

转载于:https://www.cnblogs.com/lhfen/p/6040790.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值