PoEdu-Windows班-009 多线程

线程的状态

A.       启动

1.        CONTEXT

2.        使用计数  = 2

3.        暂停计数  = 1 (为0时可进入CPU的调度,当前线程是可执行的状态)

 

B.       运行:  CPU调度

1.        执行我们的函数

a.   时不时切换线程 –>  将数据写入 CONTEXT

b.   读取CONTEXT

 

C.        挂起:  暂停线程的运行

1.        SuspendThread函数可使线程挂起,暂停计数被+1

2.        ResumeThread函数会将暂停计数-1。

3.        Remark:

a.   SuspendThread函数为非实时的,他只是提出需求,线程仍然会将此次时间片执行完,才挂起

b.   多次SuspendThread,就需要多次ResumeThread才能将暂停计数变为0,线程才能继续运行。

c.    一个良好的程序,不应该将线程挂起,因为你无法确定是否需要执行完当前时间片才挂起。

 

D.       等待休眠

1.        Sleep(100)可将线程变为等待休眠状态,此100ms(非精准)中不再被CPU调度。

2.        Sleep(-1)可将线程一直处于等待中,直到进程结束。

3.        Sleep(0),放弃剩余的执行时间。

4.        SwitchToThread(),可切换线程,具体切换由系统决定。

 

E.        消亡

1.        使用计数-1,变为1,需要调用CloseHandle函数才能将使用计数变为0,系统才会释放此线程内核对象。

2.        释放线程栈区。

3.        设置退出代码。

 


l  CONTEXT结构体

A.       获取线程上下文:

1.        GetThreadContext()函数。

2.        使用前需要设置结构体中ContextFlags的值,以便来获取哪些数据。

 

 

CreateThread()和_beginthreadex()

A.       _beginthreadex()是纯C语言的。

B.       CreateThread()是Windows的API。

C.       Remark:

1.        C语言最开始设计的时候并没有多线程的概念,所以存在很多全局变量,这些全局变量在多线程中是非安全的。_beginthreadex函数新建的线程中在堆栈多开辟了一个空间,用以存放这些全局的变量,这样每个线程都有独立的这些东西,达到线程安全,然后调用CreateThread。所以推荐使用_beginthreadex!!当然其关闭函数为_endthreadex()来关闭线程,用以释放多分配的空间。

2.        beginthreadex函数在最后会自动调用_endthreadex,无需自己调用。

 

 

原子操作

         同一资源,在同一时间只有一个线程能够访问,属于系统级的操作。

         系列函数:InterlockExchange()等等…

 

 

指定CPU运行程序

A.       指定进程:SetProcessAffinityMask(GetCurrentProcess(),0x1);

B.       指定线程:SetThreadAffinityMask(hThread,0x1)

C.       第二个参数的每一个bit表示一个CPU核,可指定多核运行。


 

旋转锁

        

使用旋转锁应该注意的地方:

1.        使用这种同步方式,我们需要保证需要同步的进程是运行在同一优先级的,如果两个线程优先级为6,另一个为4,那么优先级为4的线程不会得到等待资源的机会。

2.        应该避免资源标示和资源本身在同一告诉缓存行。

3.        应避免在单处理器的系统上使用旋转锁。

4.        上锁会导致1人做事多人围观的结果,其效果不一定有单线程快!!同时还会导致CPU运行百分百!

 

 

l  关键字volatile

A.       volatile提醒编译器它后面所定义的变量随时都有可能改变,因此编译后的程序每次需要存储或读取这个变量的时候,都会直接从变量地址中读取数据。如果没有volatile关键字,则编译器可能优化读取和存储,可能暂时使用寄存器中的值,如果这个变量由别的程序更新了的话,将出现不一致的现象

B.    一般说来,volatile用在如下的几个地方:

1.    中断服务程序中修改的供其它程序检测的变量需要加volatile;

2.    多任务环境下各任务间共享的标志应该加volatile;

3.    存储器映射的硬件寄存器通常也要加volatile说明,因为每次对它的读写都可能由不同意义


 

l  临界区

1.        InitializeCriticalSection:初始化临界区,但是此函数返回值为void,无法直接判断是否成功,如果失败,其会抛出一个异常。

2.        InitializeCriticalSectionAndSpinCount:初始化临界区,同时设置进入临界区的测试次数,返回值为BOOL。可利用此函数来初始化,解决上个函数的问题。

3.        DeleteCriticalSection:删除临界区。

4.        EnterCriticalSection:进入临界区,如果无法进入,则线程进入等待状态。

5.        TryEnterCriticalSection:尝试进入临界区,可通过其返回值来判断是否可进入,这样就可以做许多的事情了,而不是傻傻的等待。

6.        LeaveCriticalSection:离开临界区。


Silm锁

A.       InitializeSRWLock:初始化silm锁,无需delete。

B.       以独占的方式进入:


C.       以共享的方式进入:


D.       缺点:

1.        无法调度,没有try类型的函数。

2.        无法使用递归,但临界区可以递归。


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值