一、实验目的
1.掌握Windows中线程的操作。
2.熟悉线程不同步时的现象及环境因素。
3.掌握一种同步对象的使用。
二、实验理论基础及教材对应关系
1.线程和线程不同步的认识。
2.线程间的同步和通信。
3.本实验内容主要对应于操作系统教材第2章中关于线程的各节。
三、实验内容与步骤
1.定义全局变量 int i = 0; 初始值置为 0。
2.创建两个线程,一个对 i 执行加 1 操作,另一个对 i 执行减 1 操作。两个线程执行相同的次数。
显然,正常情况下,i 的仍然保持为 0。
#include <stdio.h>
#include <windows.h>
#define MaxCount 9000000 // 循环次数要很大,可多次尝试一些值
DWORD __stdcall fun1( LPVOID p1)
{
for( int j =0 ;j < MaxCount;j++){
i++;
}
return 0;
}
DWORD __stdcall fun2( LPVOID p1)
{
for( int j =0 ;j < MaxCount;j++){
i--;
}
return 0;
}
3.观察两个线程执行后的情况,可以发觉最后 i 的值不一定是 0, 有时是很大的正数,有时是很大的负数,这就是多个线程在操作同一个变量 i时,未同步时带来的严重问题。
还应该了解,在多个线程操作共享的变量时,才需要考虑同步问题。
4.给这两个线程加上同步代码,再来观察对 i 值的影响。步骤2的函数稍微改动即可:
CRITICAL_SECTION cs;
DWORD __stdcall fun1( LPVOID p1)
{
for( int j =0 ;j < MaxCount;j++){
::EnterCriticalSection(&cs);
i++;
::LeaveCriticalSection(&cs);
}
}
DWORD __stdcall fun2( LPVOID p1)
{
for( int j =0 ;j < MaxCount;j++){
::EnterCriticalSection(&cs);
i--;
::LeaveCriticalSection(&cs);
}
}
加入的同步代码的两个线程,无论如何执行,i 的值总是 0 ,结果是正确的。
5.主函数的写法
int main()
{
DWORD id1,id2;
HANDLE hThread[2];
::InitializeCriticalSection(&cs);
hThread[0] = ::CreateThread(0,0,fun1,0,0,&id1);
hThread[1] = ::CreateThread(0,0,fun2,0,0,&id2);
::WaitForMultipleObjects(2,hThread,1,INFINITE);
printf("i = %d\n",i);
::DeleteCriticalSection(&cs);
getchar();
return 0;
}
实验分析
未同步的情况:
在不包含同步代码的版本中(即原始版本的 fun1 和 fun2 函数),两个线程会并发地修改全局变量 i。
由于没有同步机制,可能会出现竞态条件,即两个线程可能同时尝试修改 i 的值,导致 i 的最终值不确定。
实验结果可能显示 i 的值为很大的正数、很大的负数或零附近的某个值,这取决于线程调度的具体方式和时机。
同步的情况:
在包含同步代码的版本中,使用了临界区来确保对 i 的访问是互斥的。
这意味着在任何时刻,只有一个线程可以进入临界区并执行加 1 或减 1 操作。
由于加 1 和减 1 操作的数量相等,且这些操作是同步进行的,因此最终 i 的值将始终为 0。
实验结果将一致地显示 i = 0。
实验结论:
本实验展示了多线程编程中同步机制的重要性。
当多个线程需要访问和修改共享资源时,必须使用适当的同步机制来避免竞态条件和不确定的行为。
临界区是一种有效的同步机制,可以确保对共享资源的互斥访问。
标签:同步,操作系统,Windows,++,int,线程,cs,实验 From: https://blog.csdn.net/m0_74107848/article/details/143161792