Windows内核模式下的线程同步

Windwos下内核模式/用户模式实现线程同步的比较
  • 在用户模式下进行线程同步的最大好处就是非常快。利用内核对象进行线程同步时,调用线程必须从用户模式切换到内核模式,此过程相对挺慢的
  • 需要在多个进程间进行线程同步时或者线程同步时希望设置超时时间,那么只能利用内核对象进行线程同步

常用等待函数
函数 功能
WaitForSingleObject Waits until the specified object is in the signaled state or the time-out interval elapses.
WaitForMultipleObjects Waits until one or all of the specified objects are in the signaled state or the time-out interval elapses.

参考资料 https://docs.microsoft.com/en-us/windows/desktop/api/synchapi/nf-synchapi-waitforsingleobject

事件内核对象
函数 功能
CreateEvent Creates or opens a named or unnamed event object
第二个参数为TRUE代表手动,为FALSE代表自动
第三个参数代表初始状态是否为触发状态
OpenEvent Opens an existing named event object.
SetEvent Sets the specified event object to the signaled state.
ResetEvent Sets the specified event object to the nonsignaled state.
情况 手动重置事件 自动重置事件
事件内核对象被触发 所有等待该事件的线程均变为可调度状态 只有一个等待该事件的线程变为可调度状态
等待事件内核对象成功的副作用 自动置为非触发状态


可等待的计时器内核对象
函数 功能
CreateWaitableTimer Creates or opens a waitable timer object.
第二个参数:TRUE表示手动重置,为FALSE表示为自动重置
OpenWaitableTimer Opens an existing named waitable timer object.
SetWaitableTimer Activates the specified waitable timer. When the due time arrives, the timer is signaled and the thread that set the timer calls the optional completion routine.
CancelWaitableTimer Sets the specified waitable timer to the inactive state.
情况 手动重置计时器 自动重置计时器
计时器内核对象被触发 所有等待该计时器内核对象的线程均变为可调度状态 只有一个等待该计时器内核对象的线程变为可调度状态
等待的副作用 自动置为非触发状态
SetWaitableTimer详解
参数 解释
HANDLE hTimer 可等待的计时器内核对象句柄
const LARGE_INTEGER *lpDueTime 第一次触发时间,可以是一个绝对时间(此时间可以已逝去),可以是一个相对调用时间(传负值,传入值必须是100纳秒的整数倍)
LONG lPeriod 间隔触发时间,单位为毫秒,传0代表只触发一次
PTIMERAPCROUTINE pfnCompletionRoutine 回调函数
LPVOID lpArgToCompletionRoutine 回调函数参数
BOOL fResume 一般为 FALSE
注意点
  • 可等待的计时器内核对象会在某一指定的时间触发,或每隔一段时间触发一次
  • 当且仅当SetWaitableTimer的调用线程处于可提醒状态时,由此函数设定的回调函数会被同一线程调用(异步过程调用,APC)。
  • 只有当所有的APC函数都处理完毕后,才会返回主调线程
  • 有关APC的调用过程,参考资料: https://docs.microsoft.com/en-us/windows/desktop/Sync/asynchronous-procedure-calls
  • 一般在使用计时器内核对象时,很少要用到APC,直接等待计时器内核对象被触发,然后做想做的事情就好了
使用示例
#include <windows.h>
#include <cstdio>

int main()
{
    HANDLE hWaitableTime = CreateWaitableTimer(nullptr, FALSE, nullptr);
 
    LARGE_INTEGER nLargeValue = {};
    SYSTEMTIME SystemTime = {};
    FILETIME aFileTime[2] = {};
    SystemTime.wYear = 2018;
    SystemTime.wMonth = 2;
    SystemTime.wDay = 6;
    SystemTime.wHour = 20;
    SystemTime.wMinute = 41;
    SystemTime.wSecond = 0;
    SystemTime.wMilliseconds = 0;
    SystemTimeToFileTime(&SystemTime, aFileTime);
    LocalFileTimeToFileTime(aFileTime, aFileTime + 1);
    nLargeValue.HighPart = aFileTime[1].dwHighDateTime;
    nLargeValue.LowPart = aFileTime[1].dwLowDateTime;
    //以上指定一个绝对时间
 
    SetWaitableTimer(hWaitableTime, &nLargeValue, 1000, 
        nullptr, nullptr, FALSE);
 
    while(true)
    {
        WaitForSingleObject(hWaitableTime, INFINITE);
        printf("Hello World\n");
    }
 
    CloseHandle(hWaitableTime);
    return 0;
    //程序每隔1s输出Hello World
}
#include <windows.h>
#include <cstdio>

void __stdcall FunTest(void* pIn, unsigned long dwTimerLowValue, unsigned long dwTimerHighValue)
{
    printf("CallBack:%d\n", ++*static_cast<int*>(pIn));
}


int main()
{
    HANDLE hWaitableTime = CreateWaitableTimer(nullptr, FALSE, nullptr);

    LARGE_INTEGER nLargeValue = {};
    nLargeValue.QuadPart = -1 * 10000000;

    int nValue = 0;
    SetWaitableTimer(hWaitableTime, &nLargeValue, 1000, FunTest, &nValue, FALSE);
    //会在此函数调用后 每隔1s调用 FunTest

    while (true)
    {
        SleepEx(1, TRUE);   //将线程置为可提醒状态
    }
    CloseHandle(hWaitableTime);

    return 0;
}


信号量内核对象
函数 功能
CreateSemaphore Creates or opens a named or unnamed semaphore object.
OpenSemaphore Opens an existing named semaphore object.
ReleaseSemaphore Increases the count of the specified semaphore object by a specified amount.
信号量的规则
  • 信号量内核对象包含一个最大资源计数和一个当前资源计数,前者代表信号量可以控制的最大资源数量,后者表示信号量当前可用资源的数量
  • 如果当前资源计数大于0,那么信号量处于触发状态
  • 如果当前资源计数等于0,那么信号量处于未触发状态
  • 当前资源计数不会变为负数且不会大于最大资源计数
  • 等待成功的副作用:当前资源计数减一


互斥量内核对象
函数 功能
CreateMutex Creates or opens a named or unnamed mutex object.
OpenMutex Opens an existing named mutex object.
ReleaseMutex Releases ownership of the specified mutex object.
互斥量内核对象的规则
  • 互斥量内核对象用来确保一个线程独占对一个资源的访问
  • 互斥量内核对象包含一个使用计数、线程ID以及一个递归计数
  • 如果互斥量内核对象的线程ID为0(无效线程ID),那么该互斥量不为任何线程所占有,处于触发状态
  • 如果互斥量内核对象的线程ID不为0,那么有一个线程已经占用了该互斥量内核对象,处于未触发状态
  • 互斥量内核对象具有线程所有权的概念,如果占用互斥量内核对象的线程在释放互斥量内核对象前终止,那么该互斥量会被当做遗弃,并且该互斥量内核对象会变为触发状态,其他线程等待此互斥量内核对象会返回WAIT_ABANDONED
  • The state of a mutex object is signaled when it is not owned by any thread. The creating thread can use the bInitialOwner flag to request immediate ownership of the mutex. Otherwise, a thread must use one of the wait functions to request ownership. When the mutex's state is signaled, one waiting thread is granted ownership, the mutex's state changes to nonsignaled, and the wait function returns. Only one thread can own a mutex at any given time. The owning thread uses the ReleaseMutex function to release its ownership.
    The thread that owns a mutex can specify the same mutex in repeated wait function calls without blocking its execution. Typically, you would not wait repeatedly for the same mutex, but this mechanism prevents a thread from deadlocking itself while waiting for a mutex that it already owns. However, to release its ownership, the thread must call ReleaseMutex once for each time that the mutex satisfied a wait.
    参考资料 https://docs.microsoft.com/en-us/windows/desktop/api/synchapi/nf-synchapi-createmutexa
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,496评论 6 501
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,407评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,632评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,180评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,198评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,165评论 1 299
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,052评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,910评论 0 274
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,324评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,542评论 2 332
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,711评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,424评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,017评论 3 326
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,668评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,823评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,722评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,611评论 2 353

推荐阅读更多精彩内容