四川李工 发表于 2018-5-30 20:14:46

windows 多线程中是否可以用判断静态变量状态实现互斥

有两个线程,调用同一个函数,未避免函数中的写入操作被两线程同时调用,加了静态变量做保护,第一个线程调用了该函数, 第二个线程需等待该函数执行完成才可调用,是否可以实现呢?有没有什么问题?。

voidfunction1(int ii)
{
           static BOOLLock1=FALSE;
        while(Lock1==TRUE)
                sleep(1);
        Lock1=TRUE;
        Write_File( ii);
        Lock1=FALSE;
}

void Thread1()
{
        function1(1);
}

void Thread2()
{
        function1(2);
}

javenreal 发表于 2018-5-30 20:35:11

用一个api中的锁,代码量也不大。

oldmen 发表于 2018-5-30 20:38:55

去看看孙鑫视频里面有一节课专门讲这个。

SkyGz 发表于 2018-5-30 20:44:48

WaitForSingleObject(g_hMutex, INFINITE);

albert.hu 发表于 2018-5-30 20:47:26

用标准线程互斥法

如果你的共用函数没有唯一需要操作的资源,则不用担心,windows会自动将函数重入的

如果有唯一需要保护的资源,你这样防不住的,你的保护操作需要几个分立的指令,中间任何时候都有可能被打断插入另外一个线程

lswood 发表于 2018-5-30 20:48:00

4楼正解,可以等待任何内核对象,包括mutex、event、file、thread、progress

redroof 发表于 2018-5-30 21:15:58

lswood 发表于 2018-5-30 20:48
4楼正解,可以等待任何内核对象,包括mutex、event、file、thread、progress

在同一个进程中用CRITICAL_SECTION最轻量级,也最快。如果没有别的特别需求,应当首选这个

四川李工 发表于 2018-5-30 21:20:49

我是否可以在子函数中使用这些标准线程互斥方法?   这样就不用在每个线程中,每处调用都写这么一段代码?

redroof 发表于 2018-5-30 21:36:30

四川李工 发表于 2018-5-30 21:20
我是否可以在子函数中使用这些标准线程互斥方法?   这样就不用在每个线程中,每处调用都写这么一段代码? ...

当然可以,而且这是最好的做法。其实你都不知道有多少个经常被你调用的库函数在内部是自带锁的,也不需要知道。
对于写库的人来说,如果他需要一把锁,就应当自己在内部做一个,不要把这个责任交给用户

四川李工 发表于 2018-5-30 21:57:25

看来我的方式不是很靠谱! 系统总共30多个线程,每几个小时就有一次数据没写成功。总结下来CRITICAL_SECTION   
WaitForSingleObject(g_hMutex, INFINITE);等方式都可以,是否确认这些互斥方式都可以写在子函数里面,而不需要每个线程调用处都写?   这问题答案 留给后面有这问题的网友吧

Scarlette 发表于 2018-5-30 22:04:34

你最初的代码就是个自旋锁的雏形,改成atomic compare and exchange就能用。不过自旋锁里面最好不要做时间很长的动作,也不需要sleep,否则效率上反而不合算。用的合理的话,自旋锁效率远高于CriticalSection,你自己衡量吧。

四川李工 发表于 2018-5-30 22:15:45

我理解是 大概意思就是互斥锁 可以释放CPU资源,但是实时性差了点,但是自旋锁占用CPU资源但是实时性好

Scarlette 发表于 2018-5-30 22:19:15

四川李工 发表于 2018-5-30 22:15
我理解是 大概意思就是互斥锁 可以释放CPU资源,但是实时性差了点,但是自旋锁占用CPU资源但是实时性好 ...

不。你要考虑切进内核态的开销,效率差异不是一星半点。

四川李工 发表于 2018-5-30 22:23:49

Scarlette 发表于 2018-5-30 22:19
不。你要考虑切进内核态的开销,效率差异不是一星半点。

您说的这句是什么意思?能否详细点?

Scarlette 发表于 2018-5-30 22:32:25

发生任务调度的时候,都是要从用户态切入内核态处理的,开销非常大。Mutex任何操作都要切入内核态处理;Critical Section在EnterCriticalSection()被Block时,以及Resume(即被阻塞线程在其他线程LeaveCriticalSection后优先级反转切回CPU)时,都会发生内核态切换。

at90s 发表于 2018-5-31 12:41:32

你这段代码并不能实现你的功能。考虑多核情况,跑在两个核上的线程可能会同时进入while循环,同时判到锁未占用。单核情况,线程1判到锁未占用,在设置锁占用标志之前,可能会被操作系统抢占,切换到线程2,线程2同样发现锁未被占用,这样两个线程就同时获得锁了。要是不想使用操作系统提供的机制,你可以研究下CAS原子操作、peterson算法、面包店算法之类的方法。其实直接用操作系统的Critical Section好了,这货会先CAS一下,发现冲突了才会陷入内核阻塞,而实际上只要临界区足够小,冲突发生的机率极小,在CAS时就会获得锁,根本不会陷入内核休眠,所以不需要担心效率问题。

shamiao 发表于 2018-5-31 12:48:50

简单的变量不能当做多线程的“锁”来用。因为你不能保证对变量的操作不被线程调度打断。

就算是 i++ 这样简单的语句,尚且分为取值-自增-回写3个步骤,从而在多线程之下不能免于被打断的命运。

更何况你这个有这么多语句!

不明确指定一种“原子行为”(锁、原子计数等)的操作都不能用于线程间同步,再简单的也不行!!!

小燕子神飞2016 发表于 2018-5-31 12:50:26

建议用标准的线程操作函数
页: [1]
查看完整版本: windows 多线程中是否可以用判断静态变量状态实现互斥