小心pthread_cond_signal和SetEvent之间的差异

ZZ FROM: http://blog.csdn.net/absurd/article/details/1402433

=====================================================

转载时请注明出处和作者联系方式:http://blog.csdn.net/absurd

作者联系方式:Li XianJing <xianjimli at hotmail dot com>

更新时间:2006-12-19

=====================================================


今天帮同事查一个多线程的BUG,其中一个线程挂在g_cond_wait上不动了。从代码来看,看出不出任何问题,g_cond_waitg_cond_signal是严格配对的。折腾了两个小时后,从LOG信息中发现,g_cond_waitg_cond_signal的顺序有点问题,一个线程先调g_cond_signal,另外一个线程才调g_cond_wait

 

g_cond_signalglib的封装,在Linux下,是用pthread_cond_signal模拟的,在Win32下,是用SetEvent模拟的。在Win32下,SetEventWaitForSingleObject在两个线程中的调用顺序没有关系,奇怪,难道在linux下两者的调用顺序有影响吗?

 

看了pthread的代码,果然如此:pthread_cond_signal发现没有其它线程等待,它直接返回了(见用红色高亮的代码)

int pthread_cond_signal(pthread_cond_t *cond)

{

    if (cond == NULL)

        return pth_error(EINVALEINVAL);

    if (*cond == PTHREAD_COND_INITIALIZER)

        if (pthread_cond_init(condNULL) != OK)

            return errno;

    if (!pth_cond_notify((pth_cond_t *)(*cond), FALSE))

        return errno;

    return OK;

}

int pth_cond_notify(pth_cond_t *condint broadcast)

{      

    /* consistency checks */

    if (cond == NULL)

        return pth_error(FALSEEINVAL);

    if (!(cond->cn_state & PTH_COND_INITIALIZED))

        return pth_error(FALSEEDEADLK);

   

    /* do something only if there is at least one waiters (POSIX semantics) */

    if (cond->cn_waiters > 0) {

        /* signal the condition */

        cond->cn_state |= PTH_COND_SIGNALED;

        if (broadcast)

            cond->cn_state |= PTH_COND_BROADCAST;

        else

            cond->cn_state &= ~(PTH_COND_BROADCAST);

        cond->cn_state &= ~(PTH_COND_HANDLED);

   

        /* and give other threads a chance to awake */

        pth_yield(NULL);

    }

 

    /* return to caller */

    return TRUE;

}

 

晚上回家后,我又看了reactos关于SetEvent的实现。结果也意料之中:没有线程等待这个Event时,它仍然会设置SignalState(见用红色高亮的代码)

LONG

STDCALL

KeSetEvent(PKEVENT Event,

           KPRIORITY Increment,

           BOOLEAN Wait)

{

    KIRQL OldIrql;

    LONG PreviousState;

    PKWAIT_BLOCK WaitBlock;

 

    DPRINT("KeSetEvent(Event %x, Wait %x)/n",Event,Wait);

 

    /* Lock the Dispathcer Database */

    OldIrql = KeAcquireDispatcherDatabaseLock();

 

    /* Save the Previous State */

    PreviousState = Event->Header.SignalState;

 

    /* Check if we have stuff in the Wait Queue */

    if (IsListEmpty(&Event->Header.WaitListHead)) {

 

        /* Set the Event to Signaled */

        DPRINT("Empty Wait Queue, Signal the Event/n");

        Event->Header.SignalState = 1;

    } else {

 

        /* Get the Wait Block */

        WaitBlock = CONTAINING_RECORD(Event->Header.WaitListHead.Flink,

                                      KWAIT_BLOCK,

                                      WaitListEntry);

 

 

        /* Check the type of event */

        if (Event->Header.Type == NotificationEvent || WaitBlock->WaitType == WaitAll) {

 

            if (PreviousState == 0) {

 

                /* We must do a full wait satisfaction */

                DPRINT("Notification Event or WaitAll, Wait on the Event and Signal/n");

                Event->Header.SignalState = 1;

                KiWaitTest(&Event->HeaderIncrement);

            }

 

        } else {

 

            /* We can satisfy wait simply by waking the thread, since our signal state is 0 now */

            DPRINT("WaitAny or Sync Event, just unwait the thread/n");

            KiAbortWaitThread(WaitBlock->ThreadWaitBlock->WaitKey, Increment);

        }

    }

 

    /* Check what wait state was requested */

    if (Wait == FALSE) {

 

        /* Wait not requested, release Dispatcher Database and return */

        KeReleaseDispatcherDatabaseLock(OldIrql);

 

    } else {

 

        /* Return Locked and with a Wait */

        KTHREAD *Thread = KeGetCurrentThread();

        Thread->WaitNext = TRUE;

        Thread->WaitIrql = OldIrql;

    }

 

    /* Return the previous State */

    DPRINT("Done: %d/n"PreviousState);

    return PreviousState;

}

 

 

而在KeWaitForSingleObject中,它发现SignalState大于0,就会Wait成功(见用红色高亮的代码)

NTSTATUS

STDCALL

KeWaitForSingleObject(PVOID Object,

                      KWAIT_REASON WaitReason,

                      KPROCESSOR_MODE WaitMode,

                      BOOLEAN Alertable,

                      PLARGE_INTEGER Timeout)

{

         ...

if (CurrentObject->Header.SignalState > 0)

        {

            /* Another satisfied object */

            KiSatisfyNonMutantWait(CurrentObject, CurrentThread);

            WaitStatus = STATUS_WAIT_0;

            goto DontWait;

        }

...

}

 

由此可见,glib封装的g_cond_signal/g_cond_waitWin32下和Linux下行为并不完全一致。即使不使用glib的封装,自己封装或者直接使用时,也要小心这个微妙的陷阱。

 

~~end~~


转载于:https://www.cnblogs.com/iplus/archive/2012/08/31/4467393.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/379364.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

eshop.sql(复制的时候注意路径!!!)

USE [master] GO /****** Object: Database [eshop] Script Date: 2019/11/25 星期一 上午 08:54:14 / CREATE DATABASE [eshop] ON PRIMARY ( NAME N’eshop_dat’, FILENAME N’D:\eshop\eshop_dat.mdf’ , SIZE 10240KB , MAXSIZE 51200KB , FILEGROWTH 5120KB ) LOG O…

doublevalue_Java Double类doubleValue()方法与示例

doublevalueDouble类doubleValue()方法 (Double class doubleValue() method) doubleValue() method is available in java.lang package. doubleValue()方法在java.lang包中可用。 doubleValue() method is used to return the value denoted by this Double object converted…

ffmpeg 命令过滤器裁剪

1 图片操作&#xff1a; 原图&#xff1a; 使用ffplay 显示左半边 ffplay -i input.png -vf cropiw/2:ih:0:0 可以通过ffmpeg 保存 ffmpeg -i input.png -vf cropiw/2:ih:0:0 out.png 2 视频操作&#xff1a; 原视频&#xff1a; 显示左半边 ffplay -i cctvhttp.flv -vf …

去除aspx生成的页面最开始的空行

使用.aspx生成的页面一般都会有一个或多个空行&#xff0c;当然这些空行不会影响页面在浏览器中的渲染结果&#xff0c;不过在查看源代码的时候感觉有些别扭&#xff0c;我曾试着去删除这些空行&#xff0c;但没有成功&#xff0c;你知道你们有没有去尝试。 1 <% Page Langu…

PUBLISH.sql(复制的时候注意路径!!!)

USE [master] – GO – /****** Object: Database [PUBLISH] Script Date: 2019/11/25 星期一 上午 09:00:04 / – CREATE DATABASE [PUBLISH] ON PRIMARY – ( NAME N’PUBLISH’, FILENAME N’F:\PUBLISH\PUBLISH.mdf’ , SIZE 51200KB , MAXSIZE UNLIMITED, FILEGROWTH …

c ++ 函数的esp指针_在C ++中通过指针访问成员函数

c 函数的esp指针Create a class along with data member and member functions and then access the member functions by using a pointer in C. 创建一个类以及数据成员和成员函数&#xff0c;然后使用C 中的指针访问成员函数。 如何通过指针访问成员函数&#xff1f; (How…

[iphone-cocos2d]分享一段Objective-C可调用的游戏中播放音乐(1)

首先需要引入AudioTool 这个framework 代码 -(id)initWithPath:(NSString *)path{ UInt32 size, maxPacketSize; char*cookie; inti; if(gThereIsAnActiveTrack) { NSLog("*** WARNING *** GBMusicTrack only plays one track at a time…

汇编语言-010(循环移位ROL,ROR 、进位循环进位RCL,RCR 、有符号数溢出 、双精度移位SHLD,SHRD、SHL和ADD计算 、位运算应用)

1 &#xff1a;循环移位ROL,ROR,带进位循环进位RCL,RCR .386 .model flat,stdcall.stack 4096 ExitProcess PROTO,dwExitCode:DWORD.code main PROC;循环左移mov al,40h ;AL 010000000brol al,1 ;AL 100000000b ,CF 0rol al,1 ;AL 000000001b ,CF 1rol al,1 ;A…

[Z]POJ 计算几何入门题目推荐[转PKKJ]

http://www.cnblogs.com/eric-blog/archive/2011/05/31/2064785.html http://hi.baidu.com/novosbirsk/blog/item/723a9727a9ab8804918f9dca.html其实也谈不上推荐&#xff0c;只是自己做过的题目而已&#xff0c;甚至有的题目尚未AC&#xff0c;让在挣扎中。之所以推荐计算几何…

2013年 833c语言程序 江南大学 (A卷)

1.编写程序实现求两个整数最大公约数和最小公倍数. 方法一&#xff1a;辗转相除法 算法思路&#xff1a;两个整数a,b,其中a>b&#xff0c;求其最大公约数和最小公倍数 步骤① a%bc,其中c为余数 步骤② 若余数c为0&#xff0c;即a可以把b给整除,也就是说这里的b就是其最大公…

二十几岁失败的原因

1.缺乏人生目标。在研究过的人们中&#xff0c;9.98%的人没有"人生目标"&#xff0c;这恐怕是人们失败的最大原因。  2.自学能力不足。历史上所谓掌握最高教育的人&#xff0c;几乎都是"自学型"的。所谓"有教育"的人&#xff0c;不能只看成是有…

C程序生成一定范围内的随机数

Random numbers just numbers that lie within a range and any of the numbers can occur. 随机数只是在一个范围内的数字&#xff0c;任何数字都可能出现。 In programming, we come through a lot of scenarios where we need to generate random numbers. Like for dice g…

提示丢失libgcc_s_dw2-1.dll问题

QT使用MinGW编译器编译中的的执行文件&#xff0c;执行问题 将qt中安装的mingw编码器的路径添加到环境变量path (D:\Qt\Qt5.10.1\5.10.1\mingw53_32\bin)

第1章 数据库系统概述

第1章 数据库系统概述 1.1 数据库系统简介 数据库技术的发展历史 人工管理阶段文件系统阶段数据库系统阶段

浅谈多线程和异步

最近很忙&#xff0c;因此拿出时间来写博客也算是忙里偷闲了&#xff0c;继承前面的一贯风格&#xff0c;继续浅谈胡侃。  最近在项目中遇到了Socket异步网络传输的问题&#xff0c;所以沉下心来整理下。于是&#xff0c;先问了下度娘&#xff0c;结果找到了园友志良的一篇文…

查看Sql Server的log文件大小

SELECT DB_NAME(database_id) AS DatabaseName,Name AS Logical_Name,Physical_Name, (size*8)/1024 SizeMBFROM sys.master_filesWHERE DB_NAME(database_id) AdventureWorksGO 转载于:https://www.cnblogs.com/top5/archive/2010/03/02/1676776.html

python调用带参函数_Python | 带有示例的函数调用类型

python调用带参函数There are following types of function calls in python: python中有以下类型的函数调用&#xff1a; Call by value 按价值致电 Call by reference 通过参考电话 1)按价值致电 (1) Call by value ) When, we call a function with the values i.e. pass …

ffmpeg 命令添加文字水印

使用ffplay 预览一下效果&#xff1a; ffplay -i cctvhttp.flv -vf “drawtextfontsize100:fontfileArial.ttf:tex t‘hello world’:x20:y20:fontcolorblue:alpha0.5” -x 640 -y 480 使用ffmpeg保存为文件 &#xff1a; ffmpeg -i cctvhttp.flv -vf “drawtextfontsize10…

jquery弹出层

这是一个弹出层的插件&#xff0c;有时候做东西的&#xff0c;经常会用到了&#xff0c;所以在次发一下&#xff0c;和大家分享一下&#xff01; [task]<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/x…

MUL与IMUL区别(微机原理与接口技术 第2版)课后习题3.14、P123

MUL与IMUL的详细区别 乘数位数隐含的被乘数乘积的存放位置举例8位ALAX中MUL BL16位AXDX与AX中&#xff08;DX存放高16位、AX存放低16位&#xff09;MUL BX 课本P97例题 一&#xff09;、将以下指令中的立即数看作是无符号数实现相乘: MOV AL,0B4H ;ALB4H180 解释以下&…