二
1) 线程的上下文切换
2)暂停的线程不可以调度。等待事件发生的线程也不能调度。
内核对象内有一个值,指明线程的暂停计数。当值为0时可以调度。
SuspendThread(hThread);
ResumeThread(hThread);
3)计算线程执行时间
4)结构环境
G e t T h r e a d C o n t e x t和S e t T h r e a d C o n t e x t函数使你能够对线程进行许多方面的控制,但是在使用它们时应该小心。实际上,几乎没有应用程序调用这些函数。增加这些函数是为了增强调试程序和其他工具的功能。任何应用程序都可以调用它们。
三线程同步用户方式
1)何时需要同步
•当有多个线程访问共享资源而不使资源被破坏时。
•当一个线程将一个任务已完成的情况通知一个或多个线程时。
2)原子访问
•线程在访问资源时确保所有其它线程不在相同时间内访问同一资源。
Long g_x = 0;
DWORD WINAPI ThreadPro1(PVOID pvParam)
{
G_x ++;
Return 0;
}
DWORD WINAPI ThreadPro2(PVOID pvParam)
{
G_x++;
Return 0;
}
上述在真正执行时变为下列汇编语句:
Mov eax [g_x]
Inc eax
Mov [g_x] eax
Mov eax [g_x]
Inc eax
Mov [g_x] eax
但是由于Windows 是抢占式调度方式,上述期待执行顺序可能变为
Mov eax [g_x]
Inc eax
Mov eax [g_x]
Inc eax
Mov [g_x] eax
Mov [g_x] eax
所以最后结果不是期待的 2 而是1 。所以需要同步。
我们需要保证上述递增的操作已原子方式进行,而不是中断的运行。
So we hope that the operation of increment above should run at atom way.not being interrupted.
InterlockedExchangeAdd()之类函数可以解决原子访问问题。
3)高速缓存行 in order to improve cpu running performance
4)关键代码段缺点:无法对多个进程中的线程进行同步
CRITICAL_SECTION cs;
InitializeCriticalSection(&cs);
DeleteCriticalSection(&cs);
EnterCriticalSection(&cs);
LeaveCriticalSection(&cs);
循环锁 InitializeCriticalSectionAndSpinCount(&cs , dword )使线程等待之前它要获得资源使循环锁迭代次数。双cpu用
使用技巧:
A 每个共享资源使用一个Critical_Section 变量
Int g_num[100];
Critical_Section g_csnum;
Int g_char[100];
Critical_Section g_cschar;
B 同时访问多个共享资源
EnterCriticalSection(&g_csnum);
EnterCriticalSection (&g_cschar);
G_num[];
G_char[] ;
LeaveCriticalSection(&g_cschar);
LeaveCriticalSection(&g_csnum);
EnterCriticalSection (&g_cschar);
EnterCriticalSection(&g_csnum);
G_num[];
G_char[] ;
LeaveCriticalSection(&g_csnum);
LeaveCriticalSection(&g_cschar);
有可能发生死锁,必须按照相同的请求对资源进行访问
C 不要长时间运行关键代码段。
SomeStruct gss;
CriticalSection cs;
EnterCriticalSection(&cs);
SendMessage(&gss);
LeaveCriticalSection(&cs);
无法确定 SendMessage 运行多久,所以最好使用下面代码:
EnterCriticalSection(&cs);
SomeStruct temp = gss;
LeaveCriticalSection(&cs);
SendMessage(temp)
用户方式同步 1 锁 2 关键代码段
四线程与内核对象同步
1 用户方式线程同步速度快,关键代码段只能对单个进程中线程同步。锁只能对单值,无法使线程进入等待模式。
2 线程可以使自己进入等待状态,直到一个对象进入已通知状态。
当线程等待的对象处于未通知状态,线程不可调度。
当线程等待的对象处于已通知状态,线程可以调度。
3 下面内核对象可以处于已通知状态和未通知状态。
进程线程作业事件可等待计时器文件修改通知文件控制台输入
信标互斥对象
4 等待函数 可使线程进入等待状态,直到一个特定的内核对象变成已通知状态。
DWORD WaitforSingleObject(HANDLE handle,dword dwmilliseconds);//等待对象,等待时间 infinite 等待无限时间
返回值 wait_object_0 等待对象变为已通知状态
Wait_timeout 超时
Wait_failed 错误的值
Dword WaitforMultipleObjects(dword dwcount , //等待多少对象
Const Handle *h,//对象地址
Bool waitall);//是否等待全部对象变为已通知
Dword millisecond);//等待时间
如果waitall 为true 则等待所有对象,返回与上相同
如果waitall 为 false 则不是等待所有对象。返回值如果不是wait_timeout 和wait_failed 则返回值是wait_object_0 到wait_object_0+dwcount -1之间的值
5 成功等待的副作用 函数返回之前,事件被设置成未通知状态。
6 事件内核对象最基本的内核对象。包含一个使用计数,一个指明事件是自动重置还是人工重置事件,一个指明是已通知还是未通知的事件。(待续)
本文探讨了线程同步的重要性和实现方法,包括线程的上下文切换、暂停与恢复,以及如何通过原子操作避免资源冲突。介绍了关键代码段的使用及限制,并对比了用户级同步与内核级同步的特点。
10万+

被折叠的 条评论
为什么被折叠?



