Windows编程中的进程线程同步

线程就是让程序有多个入口点,进程不执行代码,是线程的容器,线程都共享进程的地址空间、对象句柄、代码和数据等其他资源,操作系统为每一个运行线程安排一定的CPU时间

线程

就是让程序有多个入口点,进程不执行代码,是线程的容器。

线程都共享进程的地址空间、对象句柄、代码和数据等其他资源。

操作系统为每一个运行线程安排一定的CPU时间

GetCurrentThreadId()获取当前线程id

创建线程简单的小例子

image.png

GetCurrentThreadId()获取当前线程id

创建线程简单的小例子

image.png

CreateThread/_beginthreadex 创建线程

ExitThread/_endthreadex 退出线程

SuspendThread 挂起线程

ResumeThread 恢复线程

TerminateThread 终止线程

GetCurrentThread 获取当前线程句柄(伪)

GetCurrentThreadId 获取当前线程ID

GetExitCodeThread 获取线程退出码

image.png

同步

线程同步问题

不同线程使用同一变量

image.png

因为看汇编的话nCount++,分为三条指令

1.把数据放入ECX寄存器中

2.ECX数据加1

3.写入内存

所以线程切换的时候可能取出的是同一个nCount的值,再加一的话就等于加了一次而不是两次。这里就用到了线程同步的原理,把需要的操作的代码编程原子,要么不执行,要么执行完。

自旋锁

image.png

这样就不会发生之前的情况

对于这些原子操作的函数还有许多有加1、减一、交换指针等

image.png

那么如果有一段代码需要原子操作怎么办,我们可以使用上面的原子操作给他上锁

image.png


临界区
// Global variable
CRITICAL_SECTION CriticalSection; 
void main()
{
    ...
    // Initialize the critical section one time only.
    InitializeCriticalSection(&CriticalSection); 
    ...
    // Release resources used by the critical section object.
    DeleteCriticalSection(&CriticalSection)
}
DWORD WINAPI ThreadProc( LPVOID lpParameter )
{
    ...
    // Request ownership of the critical section.
    __try
    {
        EnterCriticalSection(&CriticalSection); 
        // Access the shared resource.
    }
    __finally
    {
        // Release ownership of the critical section.
        LeaveCriticalSection(&CriticalSection);
    }
}

CreateEvent

  1. 可以防多开,检测event的内核名

  2. 配合WaitforSingalObject,可以同步进程的代码执行

image.png

跨进程使用句柄

  1. 内核对象取名字

  2. 父子继承

  3. 复制句柄


  4. BOOL DuplicateHandle(
    HANDLE hSourceProcessHandle,
    HANDLE hSourceHandle,
    HANDLE hTargetProcessHandle,
    LPHANDLE lpTargetHandle,
    DWORD dwDesiredAccess,
    BOOL bInheritHandle,
    DWORD dwOptions
    );

信号灯和线程池

#pragma once
#include <windows.h>
#include <queue>
#include <string>
#include <mutex>
#include <sstream>
using namespace std;
class CMyThreadPool
{
public:
    CMyThreadPool();
    ~CMyThreadPool();
    bool Create()
    {    
        //创建一个信号灯/信号量
    m_hSem = CreateSemaphore(NULL,
              0,
              0x7FFFFFFF,
              NULL);
    for (int i = 0; i < 4; i++) {
        m_hThreadAry[i] =  CreateThread(NULL,
            0,
            (LPTHREAD_START_ROUTINE)ThreadFunc,
            this,
            0,
            NULL);
    }
    return true;
    }
    bool Destroy()
    {
            //CloseHandle(m_hSem);
    WaitForMultipleObjects(4, m_hThreadAry, TRUE, INFINITE);
    return true;
    }
    void addTask(string str) {
        m_mutex.lock();
        m_TaskQue.push(str);
        m_mutex.unlock();
        ReleaseSemaphore(m_hSem, 1, NULL);
    }
    string getTask() {
        lock_guard<mutex> guard(m_mutex);
        if (m_TaskQue.size() == 0) {
            return "";
        }
        string str = m_TaskQue.front();
        m_TaskQue.pop();
        return str;
    }
    HANDLE m_hThreadAry[4];
    queue<string> m_TaskQue;
    mutex m_mutex;
    HANDLE m_hSem;
};
DWORD ThreadFunc(LPVOID lpParam) {
    CMyThreadPool* pThis = (CMyThreadPool*)lpParam;
    int nThreadID = GetCurrentThreadId();
    while (WaitForSingleObject(pThis->m_hSem, INFINITE) == WAIT_OBJECT_0) {
        //取任务,并执行
        string str = pThis->getTask();
        if (!str.empty()) {
            stringstream sStr;
            sStr << nThreadID << ": " <<str.c_str();
            OutputDebugStringA(sStr.str().c_str());
        }
    }
    return 0;
}




#include "stdafx.h"
#include <windows.h>
#include "MyThreadPool.h"
int main()
{
    CMyThreadPool pool;
    pool.Create();
    char buffer[20] = {0};
    for (int i = 0; i < 1000; i++) {
        memset(buffer, 0, 20);
        _itoa_s(i, buffer, 10);
        pool.addTask(buffer);
    }
    pool.Destroy();
    return 0;
}


转载请说明出处
草堂教程网 » Windows编程中的进程线程同步

发表评论

欢迎 访客 发表评论

一个纯粹的精品教程收录分享站点

查看演示 官网购买