任务一 实现批处理
一、基本信息
实践题目:实现批处理
二、实践内容简要描述
实践目标:
(1)了解Windows2000操作系统的基本结构
(2)学会在Win32环境下,通过函数 BOOL CreateProcess(LPCTSTR lpApplicationName,LPTSTR lpCommandLine, LPSECURITY_ATTRIBUTES lpProcessAttributes, LPSECURITY_ATTRIBUTES lpThreadAttributes, BOOL bInheritHandles, DWORD dwCreationFlags, LPVOID lpEnvironment, LPCTSTR lpCurrentDirectory, LPSTARTUPINFO lpStartupInfo, LPPROCESS_INFORMATION lpProcessInformation)创建进程。
(3)学会用CreateFile ReadFile读文件,用FormatMessage处理出错信息。
实践内容:
从batch文件中正确读入应用程序命令行及其参数,并依次为其创建相应进程。
三、实践报告主要内容
设计思路:
(1)先打开文件 :使用CreateFile打开一个文件,获得HANDLE hFile
(2)然后读取文件 :用ReadFile通过已经获得HANDLE hFile的读取文件,并赋给inBuffer
(3)格式或处理读取信息并创建进程 :将inBuffer 中的信息格式化提取并用CreateProcess创建进程
主要代码结构:
/* 1.create the file and get the handle*/
HANDLE hFile=CreateFile("batch",GENERIC_READ,FILE_SHARE_READ,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,0);
/* 2.judge if the file is open and get the error imformation */
if(hFile==INVALID_HANDLE_VALUE)
{
LPVOID lpMsgBuf;
FormatMessage(
FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_IGNORE_INSERTS,
NULL,
GetLastError(),
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
(LPTSTR) &lpMsgBuf,
0,
NULL
);
fprintf(stdout,(char*)(lpMsgBuf));
ExitProcess(1);
}
/* 3.read file and detect the error infomation */
BOOL bResult;
char inBuffer[1000]; // pointer to buffer that receives data
DWORD nBytesToRead=900; // number of bytes to read
DWORD nBytesRead;
LPDWORD lpnBytesRead=&nBytesRead; // pointer to number of bytes read
bResult =ReadFile(
hFile, // handle of file to read
inBuffer, // pointer to buffer that receives data
nBytesToRead, // number of bytes to read
lpnBytesRead, // pointer to number of bytes read
NULL // pointer to structure for data
);
/* 4.get the command from the buffer */
count=0;
pos=0;
for (i=0;i<(int)nBytesRead;i++)
{
if(inBuffer[i]!=10 && inBuffer[i]!=13)
{
cmdLine[count][pos]=inBuffer[i];
pos++;
continue;
}
if(inBuffer[i]==10)
{
cmdLine[count][pos]=0;
pos=0;
count++;
}
}
/* 5.copy the command from command line parameters */
for ( i = 0; i < count ; i++) {
if(!CreateProcess(
lpApplicationName, /* File name of executable */
cmdLine[i], /* Command line */
processSA, /* Process inherited security */
threadSA, /* Thread inherited security */
shareRights, /* Right propagation */
creationMask, /* Various creation flags */
environment, /* Environment variabkesr */
curDir, /* Child's current directory */
&startInfo,
&processInfo
)
) {
fprintf(stderr,"CreatProcess failed on error %d\n",GetLastError());
ExitProcess(1);
};
fprintf(stdout,"The Child Process's PID: %d.\n", processInfo.dwProcessId);
fprintf(stdout,"The Parent Process finish.\n");
Sleep(500);
CloseHandle(processInfo.hProcess);
CloseHandle(processInfo.hThread);
};
四、实践结果
基本数据:
源程序代码行数 完成实践投入的总时间 编程调试时间 源程序文件
116 2.5小时 0.5小时 ex1.cpp
测试数据设计:
“batch”文件内容如下:
c:\windows\notepad.exe
c:\windows\system32\calc.exe
c:\windows\system32\mspaint.exe
测试结果分析:
程序能够依次打开notepad,calc和mspaint,并显示
The Child Process's PID: 1712.
The Parent Process finish.
The Child Process's PID: 3276.
The Parent Process finish.
The Child Process's PID: 3876.
The Parent Process finish.
五、实践体会
第1个任务比较简单,我参考样例程序并查阅有关资料,在这个实验上没有遇到比较棘手的问题,通过任务1,我了解了创建进程的方法,对创建进程CreateProcess()函数中的各个参数有了一个初步的认识。
任务二 软件方法解决临界区问题
一、基本信息
实践题目:软件方法解决临界区问题-兄弟问题
二、实践内容简要描述
实践目标:
用软件方法(Peterson算法或Dekker算法等)解决临界区问题-兄弟问题。
实践内容:
设置竞争条件:
定义两个全局变量:accnt1和accnt2,初值都为零;
创建两个线程acc1和acc2;
(1)获得一个随机数
(2)从accnt1减去这个随机数;
(3)将这个随机数加到accnt2中;
(4)正确的话,accnt1+accnt2=0。
设置条件使其不正确。
用软件方法实现协作线程,以解决以上临界区问题,即兄弟问题。
三、实践报告主要内容
设计思路:
选择算法:
Dekker算法——该算法主要用于解决两个线程的临界区问题,是典型的软件方法解决临界区问题的算法。
设计思路:
线程Pi结构如下:
do{
flag[i]=true;
while(flag[j]){
if(turn==j) {
flag[i] = false;
while(turn==j);
flag[i]=true;
}
}
critical section
turn=j;
flag[i]=false;
remainder section
}while(1);
每个在进入临界区前用entry section实行判断等待,离开临界区后发出信号通知别的线程可以进入临界区,这样可以防止两个线程同时访问临界区。
在程序中i表示自身线程序号,再用两个线程序号之和减去i即可表示另外那个线程的序号。
主要数据结构:
struct ThreadInfo
{
int serial;
double delay;
};//存放线程的ID及其执行延时(模拟兄弟在外创业的时间)
/*volatile*/ int accnt1 = 0; //借款帐户中金额
/*volatile*/ int accnt2 = 0; //还款帐户中金额
/*volatile*/ int accnt; //借款帐户与还款帐户金额总和,应保持为0
/* variables for Dekker's arithmetic */
BOOL flag[2]={false,false};// flag[i] = true表示线程Pi 准备进入临界区
int turn; // turn = i表示线程Pi允许在临界区执行
int i = m_serial; // 自身线程序号
int j = 1 - m_serial; // 另外那个线程序号
主要代码结构:
do{
entry section
critical section
exit section
remainder section
}while(1);
主要代码分析:
1.entry section用于在进入临界区时的等待
/* entry section begin */
flag[m_serial]=true;
turn=1-m_serial;
while (flag[1-m_serial] && turn==1-m_serial);
/* entry section end */
2.exit section用于离开临界区后的发送信号的工作,通知另外的线程可以进入临界区
/* exit section begin */
flag[m_serial]=false;
/* exit section end */
四、实践结果
基本数据:
源程序代码行数 完成实践投入的总时间 资料查阅时间 编程调试时间 源程序文件
196 0.5小时 0.3小时 0.2小时 ex2.cpp
测试数据设计:
“ex2.dat”文件内容如下:
0 1
0 1
测试结果分析:
运行结果图如下所示:
Now, We begin to read thread Information to thread_info array
I am thread 0 , I am doing 00000th step
Now the random number is 20571 ; and accnt1+accnt2 = 00000
I am thread 1 , I am doing 00000th step
Now the random number is 17781 ; and accnt1+accnt2 = 00000
I am thread 0 , I am doing 00001th step
Now the random number is 22438 ; and accnt1+accnt2 = 00000
I am thread 1 , I am doing 00001th step
Now the random number is 17547 ; and accnt1+accnt2 = 00000
I am thread 0 , I am doing 00002th step
Now the random number is 27554 ; and accnt1+accnt2 = 00000
I am thread 1 , I am doing 00002th step
Now the random number is 25718 ; and accnt1+accnt2 = 00000
I am thread 0 , I am doing 00003th step
Now the random number is 18778 ; and accnt1+accnt2 = 00000
I am thread 1 , I am doing 00003th step
Now the random number is 8063 ; and accnt1+accnt2 = 00000
I am thread 0 , I am doing 00004th step
Now the random number is 30162 ; and accnt1+accnt2 = 00000
I am thread 1 , I am doing 00004th step
Now the random number is 29448 ; and accnt1+accnt2 = 00000
I am thread 0 , I am doing 00005th step
Now the random number is 7046 ; and accnt1+accnt2 = 00000
I am thread 1 , I am doing 00005th step
Now the random number is 8096 ; and accnt1+accnt2 = 00000
I am thread 0 , I am doing 00006th step
Now the random number is 16582 ; and accnt1+accnt2 = 00000
I am thread 1 , I am doing 00006th step
Now the random number is 8806 ; and accnt1+accnt2 = 00000
I am thread 0 , I am doing 00007th step
Now the random number is 1534 ; and accnt1+accnt2 = 00000
I am thread 1 , I am doing 00007th step
Now the random number is 31418 ; and accnt1+accnt2 = 00000
I am thread 0 , I am doing 00008th step
Now the random number is 21293 ; and accnt1+accnt2 = 00000
I am thread 1 , I am doing 00008th step
Now the random number is 9811 ; and accnt1+accnt2 = 00000
I am thread 0 , I am doing 00009th step
Now the random number is 22034 ; and accnt1+accnt2 = 00000
At last of thread 0 accnt1+accnt2 = 00000
I am thread 1 , I am doing 00009th step
Now the random number is 20276 ; and accnt1+accnt2 = 00000
At last of thread 1 accnt1+accnt2 = 00000
All threads have finished Operating.
Press any key to finish this Program.
五、实践体会
解决线程同步问题的关键是避免两个以上线程同时访问临界区数据,在实验中,由于entry section 和exit section所放位置不对导致了很多的错误,将entry section放在读取帐户数据后会出现读取数据出错导致帐户总额不对,因为可能读取到的是脏数据,将读取帐户数据和对其进行修改的代码放在entry section和exit section之间,即可确保同时只能有一个线程对其访问和操作,从而正确解决了问题。
六、参考文献
1、MSDN
2、《操作系统概念(第六版 影印版)》,Abraham Silberschatz、Peter Baer Galvin、Greg Gagne,
高等教育出版社
附:源程序代码
#include <windows.h>
#include <conio.h>
#include <stdlib.h>
#include <fstream.h>
#include <stdio.h>
#include <time.h>
#define INTE_PER_SEC 500
#define MAX_THREAD_NUM 64
#define RIGHT_VERSION TRUE
#define WRONG_VERSION FALSE
struct ThreadInfo
{
int serial;
double delay;
};
/*volatile*/ int accnt1 = 0;
/*volatile*/ int accnt2 = 0;
/*volatile*/ int accnt;
BOOL flag[2]={false,false};
int turn;
void account( char* file,BOOL version);
void acc_right(void* p);
void acc_wrong(void* p);
////////////////////////////////////////////////////////
// main function
////////////////////////////////////////////////////////
int main( int agrc, char* argv[] )
{
char ch;
while ( TRUE )
{
// Clear screen
system( "cls" );
// display prompt info
printf("*********************************************\n");
printf(" 1.Start the right version(with the PETERSON algorithm)\n");
printf(" 2.Start the wrong version(without any algorithm of synchronization)\n");
printf(" 3.Exit to Windows\n");
printf("*********************************************\n");
printf("Input your choice(1,2or3): ");
// if the number inputed is error, retry!
do
{
ch = (char)_getch();
}while ( ch != '1' && ch != '2'&& ch != '3');
system ( "cls" );
if ( ch == '1')
account("ex2.dat",RIGHT_VERSION);
else if (ch =='2')
account("ex2.dat",WRONG_VERSION);
else if ( ch == '3')
return 0;
printf("\nPress any key to finish this Program. \n");
_getch();
} //end while
} //end main
void account( char* file,BOOL version)
{
DWORD n_thread = 0;
DWORD thread_ID;
DWORD wait_for_all;
// Tread Object Array
HANDLE h_Thread[MAX_THREAD_NUM];
ThreadInfo thread_info[MAX_THREAD_NUM];
ifstream inFile;
inFile.open(file); //open file
printf( "Now, We begin to read thread Information to thread_info array \n\n" );
while ( inFile )
{
// read every thread info
inFile>>thread_info[n_thread].serial;
inFile>>thread_info[n_thread++].delay;
inFile.get();
} //end while
// initialize the data
srand((unsigned)time(NULL));
accnt1=0;
accnt2=0;
// Create all thread
if (version==RIGHT_VERSION)
{
for ( int i = 0; i < (int)(n_thread); i++)
{
// Create a thread
h_Thread[i] = CreateThread( NULL, 0, (LPTHREAD_START_ROUTINE)(acc_right), &thread_info[i], 0, &thread_ID);
} //end for
} else
{
for ( int i = 0; i < (int)(n_thread); i++)
{
// Create a thread
h_Thread[i] = CreateThread( NULL, 0, (LPTHREAD_START_ROUTINE)(acc_wrong), &thread_info[i], 0, &thread_ID);
} //end for
}
// Create thread
// waiting all thread will been finished
wait_for_all = WaitForMultipleObjects(n_thread,h_Thread,TRUE, -1);
printf("All threads have finished Operating.\n");
}// end account
void acc_right(void* p)
{
DWORD m_delay;
int m_serial;
int tmp1 , tmp2, rand_num;
int counter = 0;
//get info from para
m_serial = ((ThreadInfo*) (p)) -> serial;
m_delay = (DWORD) (((ThreadInfo*)(p)) -> delay*INTE_PER_SEC);
do
{
flag[m_serial]=true;
turn=1-m_serial;
while (flag[1-m_serial] && turn==1-m_serial);
//begin critical_section
printf("I am thread %d , I am doing %05dth step\n",m_serial,counter);
tmp1 = accnt1;
tmp2 = accnt2;
rand_num = rand();
accnt1 = tmp1 - rand_num;
Sleep(m_delay);
accnt2 = tmp2 + rand_num;
accnt = accnt1 + accnt2;
//critical_section end
flag[m_serial]=false;
counter++;
printf("Now the random number is %d ; and accnt1+accnt2 = %05d\n\n",rand_num,accnt);
} while (counter<10);
printf("At last of thread %d accnt1+accnt2 = %05d\n",m_serial,accnt);
} //end acc_right
void acc_wrong(void* p)
{
DWORD m_delay;
int m_serial;
int tmp1 , tmp2, rand_num;
int counter = 0;
//get info from para
m_serial = ((ThreadInfo*) (p)) -> serial;
m_delay = (DWORD) (((ThreadInfo*)(p)) -> delay*INTE_PER_SEC);
do
{
//begin critical_section
printf("I am thread %d , I am doing %05dth step\n",m_serial,counter);
tmp1 = accnt1;
tmp2 = accnt2;
rand_num = rand();
accnt1 = tmp1 - rand_num;
Sleep(m_delay);
accnt2 = tmp2 + rand_num;
accnt = accnt1 + accnt2;
//critical_section end
counter++;
printf("Now the random number is %d ; and accnt1+accnt2 = %05d\n\n",rand_num,accnt);
} while (counter<10);
printf("At last of thread %d accnt1+accnt2 = %05d\n",m_serial,accnt);
} //end acc_wrong
任务三 同步对象解决临界区问题
一、基本信息
实践题目:同步对象解决临界区问题-兄弟问题
二、实践内容简要描述
实践目标:
学会使用Win32同步对象(临界区内核对象、信号量内核对象等);
用同步对象解决临界区问题-兄弟问题。
实践内容:
设置竞争条件:
定义两个全局变量:accnt1和accnt2,初值都为零;
创建两个线程acc1和acc2;
(1)获得一个随机数
(2)从accnt1减去这个随机数;
(3)将这个随机数加到accnt2中;
(4)正确的话,accnt1+accnt2=0。
设置条件使其不正确。
用Win32提供的同步对象实现两个线程的协作,以解决以上临界区问题,即兄弟问题。
三、实践报告主要内容
设计思路:
用一个临界区变量可以实现两个线程对临界区的访问,在每个线程进入临界区前调用EnterCriticalSection函数申请权限,离开临界区后调用LeaveCriticalSection函数释放资源从而让其他线程可以访问,这样可以阻止两个线程同时处于临界区。
主要数据结构:
struct ThreadInfo
{
int serial;
double delay;
};//存放线程的ID及其执行延时(模拟兄弟在外创业的时间)
/*volatile*/ int accnt1 = 0; //借款帐户中金额
/*volatile*/ int accnt2 = 0; //还款帐户中金额
/*volatile*/ int accnt; //借款帐户与还款帐户金额总和,应保持为0
CRITICAL_SECTION g_cs; //临界区变量,用于两个线程的互斥访问
主要代码结构:
do{
entry section
critical section
exit section
remainder section
}while(1);
主要代码分析:
1.entry section用于在进入临界区时的等待
EnterCriticalSection(&my_section);
2.exit section用于离开临界区后的发送信号的工作,通知另外的线程可以进入临界区
LeaveCriticalSection(&my_section);
四、实践结果
基本数据:
源程序代码行数 完成实践投入的总时间 资料查阅时间 编程调试时间 源程序文件
193 0.2小时 0.1小时 0.1小时 ex3.cpp
测试数据设计:
“ex3.dat”文件内容如下:
0 1
1 1
2 1
3 1
4 1
测试结果分析:
运行结果图如下所示:
Now, We begin to read thread Information to thread_info array
I am thread 0 , I am doing 00000th step
I am thread 1 , I am doing 00000th step
Now the random number is 22413 ; and accnt1+accnt2 = 00000
I am thread 2 , I am doing 00000th step
Now the random number is 17802 ; and accnt1+accnt2 = 00000
I am thread 3 , I am doing 00000th step
Now the random number is 5286 ; and accnt1+accnt2 = 00000
I am thread 4 , I am doing 00000th step
Now the random number is 23304 ; and accnt1+accnt2 = 00000
I am thread 0 , I am doing 00001th step
Now the random number is 12270 ; and accnt1+accnt2 = 00000
I am thread 1 , I am doing 00001th step
Now the random number is 12170 ; and accnt1+accnt2 = 00000
I am thread 2 , I am doing 00001th step
Now the random number is 4729 ; and accnt1+accnt2 = 00000
I am thread 3 , I am doing 00001th step
Now the random number is 28247 ; and accnt1+accnt2 = 00000
I am thread 4 , I am doing 00001th step
Now the random number is 3819 ; and accnt1+accnt2 = 00000
I am thread 0 , I am doing 00002th step
Now the random number is 2578 ; and accnt1+accnt2 = 00000
I am thread 1 , I am doing 00002th step
Now the random number is 21931 ; and accnt1+accnt2 = 00000
I am thread 2 , I am doing 00002th step
Now the random number is 170 ; and accnt1+accnt2 = 00000
I am thread 3 , I am doing 00002th step
Now the random number is 18300 ; and accnt1+accnt2 = 00000
I am thread 4 , I am doing 00002th step
Now the random number is 2054 ; and accnt1+accnt2 = 00000
I am thread 0 , I am doing 00003th step
Now the random number is 538 ; and accnt1+accnt2 = 00000
I am thread 1 , I am doing 00003th step
Now the random number is 12469 ; and accnt1+accnt2 = 00000
I am thread 2 , I am doing 00003th step
Now the random number is 7825 ; and accnt1+accnt2 = 00000
I am thread 3 , I am doing 00003th step
Now the random number is 14181 ; and accnt1+accnt2 = 00000
I am thread 4 , I am doing 00003th step
Now the random number is 5984 ; and accnt1+accnt2 = 00000
I am thread 0 , I am doing 00004th step
Now the random number is 17150 ; and accnt1+accnt2 = 00000
I am thread 1 , I am doing 00004th step
Now the random number is 15529 ; and accnt1+accnt2 = 00000
At last of thread 0 accnt1+accnt2 = 00000
I am thread 2 , I am doing 00004th step
Now the random number is 31878 ; and accnt1+accnt2 = 00000
At last of thread 1 accnt1+accnt2 = 00000
I am thread 3 , I am doing 00004th step
Now the random number is 3842 ; and accnt1+accnt2 = 00000
At last of thread 2 accnt1+accnt2 = 00000
I am thread 4 , I am doing 00004th step
Now the random number is 5953 ; and accnt1+accnt2 = 00000
At last of thread 3 accnt1+accnt2 = 00000
Now the random number is 23968 ; and accnt1+accnt2 = 00000
At last of thread 4 accnt1+accnt2 = 00000
All threads have finished Operating.
Press any key to finish this Program.
程序运行过程中,线程1或线程2向accnt1中借款,一定延时后向accnt2中还款,总额accnt均为0,程序运行结果完全正确。
五、实践体会
使用临界区变量解决临界区问题实现起来比软件方法简单明了,并且可以应用到多进程的情况之中,通过这次实验我基本了解了临界区变量的使用方法和作用,其实,解决临界区问题的方法相当的多,从中选取一种合适的是要很多经验积累的。
六、参考文献
1、MSDN
附:源程序代码
#include <windows.h>
#include <conio.h>
#include <stdlib.h>
#include <fstream.h>
#include <stdio.h>
#include <time.h>
#define INTE_PER_SEC 500
#define MAX_THREAD_NUM 64
#define RIGHT_VERSION TRUE
#define WRONG_VERSION FALSE
CRITICAL_SECTION my_section;
struct ThreadInfo
{
int serial;
double delay;
};
/*volatile*/ int accnt1 = 0;
/*volatile*/ int accnt2 = 0;
/*volatile*/ int accnt;
void account( char* file,BOOL version);
void acc_right(void* p);
void acc_wrong(void* p);
////////////////////////////////////////////////////////
// main function
////////////////////////////////////////////////////////
int main( int agrc, char* argv[] )
{
char ch;
while ( TRUE )
{
// Clear screen
system( "cls" );
// display prompt info
printf("*********************************************\n");
printf(" 1.Start the right version(with the using of CRITICAL_SECTION)\n");
printf(" 2.Start the wrong version(without any algorithm of synchronization)\n");
printf(" 3.Exit to Windows\n");
printf("*********************************************\n");
printf("Input your choice(1 、2 or 3): ");
// if the number inputed is error, retry!
do
{
ch = (char)_getch();
}while ( ch != '1' && ch != '2'&& ch != '3');
system ( "cls" );
if ( ch == '1')
account("ex3.dat",RIGHT_VERSION);
else if (ch =='2')
account("ex3.dat",WRONG_VERSION);
else if ( ch == '3')
return 0;
printf("\nPress any key to finish this Program. \n");
_getch();
} //end while
} //end main
void account( char* file,BOOL version)
{
DWORD n_thread = 0;
DWORD thread_ID;
DWORD wait_for_all;
// Tread Object Array
HANDLE h_Thread[MAX_THREAD_NUM];
ThreadInfo thread_info[MAX_THREAD_NUM];
ifstream inFile;
inFile.open(file); //open file
printf( "Now, We begin to read thread Information to thread_info array \n\n" );
while ( inFile )
{
// read every thread info
inFile>>thread_info[n_thread].serial;
inFile>>thread_info[n_thread++].delay;
inFile.get();
} //end while
// initialize the data
srand((unsigned)time(NULL));
accnt1=0;
accnt2=0;
// Create all thread
if (version==RIGHT_VERSION)
{
InitializeCriticalSection(&my_section); //init critical section
for ( int i = 0; i < (int)(n_thread); i++)
{
// Create a thread
h_Thread[i] = CreateThread( NULL, 0, (LPTHREAD_START_ROUTINE)(acc_right), &thread_info[i], 0, &thread_ID);
} //end for
} else
{
for ( int i = 0; i < (int)(n_thread); i++)
{
// Create a thread
h_Thread[i] = CreateThread( NULL, 0, (LPTHREAD_START_ROUTINE)(acc_wrong), &thread_info[i], 0, &thread_ID);
} //end for
}
// Create thread
// waiting all thread will been finished
wait_for_all = WaitForMultipleObjects(n_thread,h_Thread,TRUE, -1);
printf("All threads have finished Operating.\n");
}// end account
void acc_right(void* p)
{
DWORD m_delay;
int m_serial;
int tmp1 , tmp2, rand_num;
int counter = 0;
//get info from para
m_serial = ((ThreadInfo*) (p)) -> serial;
m_delay = (DWORD) (((ThreadInfo*)(p)) -> delay*INTE_PER_SEC);
do
{
EnterCriticalSection(&my_section);
//begin critical_section
printf("I am thread %d , I am doing %05dth step\n",m_serial,counter);
tmp1 = accnt1;
tmp2 = accnt2;
rand_num = rand();
accnt1 = tmp1 - rand_num;
Sleep(m_delay);
accnt2 = tmp2 + rand_num;
accnt = accnt1 + accnt2;
//critical_section end
LeaveCriticalSection(&my_section);
counter++;
printf("Now the random number is %d ; and accnt1+accnt2 = %05d\n\n",rand_num,accnt);
} while (counter<5);
printf("At last of thread %d accnt1+accnt2 = %05d\n",m_serial,accnt);
} //end acc_right
void acc_wrong(void* p)
{
DWORD m_delay;
int m_serial;
int tmp1 , tmp2, rand_num;
int counter = 0;
//get info from para
m_serial = ((ThreadInfo*) (p)) -> serial;
m_delay = (DWORD) (((ThreadInfo*)(p)) -> delay*INTE_PER_SEC);
do
{
//begin critical_section
printf("I am thread %d , I am doing %05dth step\n",m_serial,counter);
tmp1 = accnt1;
tmp2 = accnt2;
rand_num = rand();
accnt1 = tmp1 - rand_num;
Sleep(m_delay);
accnt2 = tmp2 + rand_num;
accnt = accnt1 + accnt2;
//critical_section end
counter++;
printf("Now the random number is %d ; and accnt1+accnt2 = %05d\n\n",rand_num,accnt);
} while (counter<5);
printf("At last of thread %d accnt1+accnt2 = %05d\n",m_serial,accnt);
} //end acc_wrong
任务四 同步对象解决有限缓冲区问题
一、基本信息
实践题目:同步对象解决有限缓冲区问题
二、实践内容简要描述
实践目标:
用Win32提供的同步对象解决有限缓冲区问题
实践内容:
写一个线程实现C/C++语言程序:一些线程负责找出某个数据范围的素数,并放到一个数组中,另一些线程负责将数组中的素数按次序取出,并显示出来。显示过的数据要从数组中删除。
要求定义一个全局变量的数组:int prime[9]用于存放找到的待显示的素数。
三、实践报告主要内容
设计思路:
找min和max之间素数算法
从min开始到max的每个数num,用2,3,…,sqrt(num)来除它,如果均不能整除则num为素数。
2.进程同步:生产者-消费者算法
do{
……
Produce n item in nexp
……
Wait(empty);
Wait(mutex);
……
Add nexp to buffer
……
Signal(mutex);
Signal(full);
}while(1);
3.产生和显示素数的过程
读写时display和search线程均从prime的第0个元素开始(具体见程序代码)。Prime数组的元素为0即表明没有写入,非0即为已写入。search线程从下标0开始存放找到的素数,存放前先判断prime[i]是否为0,为0则存放新找到的素数,否则循环;display线程从下标0开始显示数组中存放的素数,显示时先判断prime[i]是否为0,不为0则显示该素数,并将prime[i]赋0,否则循环。
整数searchCount和displayCount用于记录display线程和search线程开启的个数,以便保证display线程显示素数和find线程存放素数不会发生死锁,每次测试时分别将它们初始化为0。主要数据结构:
线程信息结构体:
struct ThreadInfo
{
int serial; //ID
char command; //命令
int num_from; //起始数或显示数
int num_to; //结束数
};
int searchCount = 0; //search线程数
int displayCount = 0; //display线程数
CRITICAL_SECTION my_section; //临界区
int prime[9];
主要代码分析:
详见代码注释。
四、实践结果
基本数据:
源程序代码行数 完成实践投入的总时间 资料查阅时间 编程调试时间 源程序文件
354 4小时 1小时 3小时 ex4.cpp
测试数据设计:
“ex4.dat”文件内容如下:
1.
1 w 10 100
2 w 1 10
3 d 3 0
测试结果分析:
对应于数据2的运行结果图如下所示:
Reader Priority:
Search thread 1 begins to write the date .
Search thread 1 finish writing the date .
Search thread 1 begins to write the date .
Search thread 1 finish writing the date .
Search thread 1 begins to write the date .
Search thread 1 finish writing the date .
Search thread 1 begins to write the date .
Search thread 1 finish writing the date .
Search thread 1 begins to write the date .
Search thread 1 finish writing the date .
Search thread 2 begins to write the date .
Search thread 2 finish writing the date .
Search thread 2 begins to write the date .
Search thread 2 finish writing the date .
Search thread 2 begins to write the date .
Search thread 2 finish writing the date .
Display thread 3 begins to output prime num .
----------Display thread 3 output the prime num "11".
Display thread 3 finishes outputting prime num .
Display thread 3 begins to output prime num .
----------Display thread 3 output the prime num "13".
Display thread 3 finishes outputting prime num .
Display thread 3 begins to output prime num .
----------Display thread 3 output the prime num "17".
Display thread 3 finishes outputting prime num .
Search thread 1 begins to write the date .
Search thread 1 finish writing the date .
Search thread 1 begins to write the date .
Search thread 1 finish writing the date .
Search thread 1 begins to write the date .
Search thread 1 finish writing the date .
Search thread 1 begins to write the date .
Search thread 1 finish writing the date .
All search and display thread have finished Operating.
The array at last.
29 31 37 19 23 3 5 7 41
Press any key to finish this Program.
Thank you test this Program!
程序运行过程中,线程1、线程2为找素数线程,线程3负责显示,它们均交叉访问临界区,程序运行结果完全正确。
五、实践体会
同类线程之间的互斥以及不同类线程之间的同步需要通过两组互斥对象来解决,我在这个问题的处理上采用了semaphore和critical_section这两种对象来完成这个任务。
实践中遇到了比较大的困难:
1. 没有处理死锁的情况
死锁情况有两种,display线程过多导致不够显示,search线程过多导致不够写入,在这个问题上,我没采用等待超时的方法,而是用了全局变量来记录开启的线程数加上数据上的判断来避免死锁。
没有将handle close导致没有清空
当程序第二次运行时会出现莫名的错误,寻找了好久,才发现没有把申请的HANDLE close掉。
通过这个程序的实践,掌握了semaphore的使用以及mutex的使用。
六、参考文献
1、MSDN
2、《操作系统概念(第六版 影印版)》,Abraham Silberschatz、Peter Baer Galvin、Greg Gagne,
高等教育出版社
附:源程序代码
#include <windows.h>
#include <conio.h>
#include <fstream.h>
#include <stdio.h>
#include <math.h>
#define INTE_PER_SEC 1000
#define MAX_THREAD_NUM 64
#define MAX_FILE_NUM 32
#define MAX_STR_LEN 32
int searchCount = 0;
int displayCount = 0;
CRITICAL_SECTION my_section;
struct ThreadInfo
{
int serial;
char command;
int num_from;
int num_to;
};
int prime[9];
void GetCommand( char* file );
void thd_display(void* p);
void thd_search(void* p);
BOOL IsPrime(int num);
int GetUsed(int num[9]);
////////////////////////////////////////////////////////
// main function
////////////////////////////////////////////////////////
int main( int agrc, char* argv[] )
{
char ch;
while ( TRUE )
{
// Clear screen
system( "cls" );
// display prompt info
printf("*********************************************\n");
printf(" 1.Test for prime number search and display\n");
printf(" 2.Exit to Windows\n");
printf("*********************************************\n");
printf("Input your choice(1or2): ");
// if the number inputed is error, retry!
do
{
ch = (char)_getch();
}while ( ch != '1' && ch != '2');
system ( "cls" );
if ( ch == '1')
GetCommand("ex4.dat");
else if ( ch == '2')
return 0;
printf("\nPress any key to finish this Program. \nThank you test this Program!\n");
_getch();
} //end while
} //end main
BOOL IsPrime(int num)
{
int i=0;
if (num<2)
{
return FALSE;
}
for (i=2;i<=sqrt(num)+1;i++)
{
if (num % i == 0)
{
return FALSE;
}
}
return TRUE;
}
int GetUsed(int num[9])
{
int i,count=0;
for(i=0;i<9;i++)
{
if(num[i]!=0)
count++;
}
return count;
}
void GetCommand( char* file )
{
DWORD n_thread = 0;
DWORD thread_ID;
DWORD wait_for_all;
int i;
// Tread Object Array
HANDLE h_Thread[MAX_THREAD_NUM];
ThreadInfo thread_info[MAX_THREAD_NUM];
searchCount = 0; //init search thread count
displayCount = 0; //init display thread count
InitializeCriticalSection(&my_section); //init critical section
memset(prime,0,sizeof(prime));
ifstream inFile;
inFile.open(file); //open file
printf( "Reader Priority:\n\n" );
while ( inFile )
{
// read every reader/writer info
inFile>>thread_info[n_thread].serial;
inFile>>thread_info[n_thread].command;
inFile>>thread_info[n_thread].num_from;
inFile>>thread_info[n_thread++].num_to;
inFile.get();
} //end while
for ( i = 0; i < (int)(n_thread); i++)
{
if(thread_info[i].command == 'W' || thread_info[1].command == 'w')
{
searchCount++;
}
else if(thread_info[i].command == 'D' || thread_info[1].command == 'd')
{
displayCount++;
}
}
/* create semaphore */
HANDLE h_semaphore_f = CreateSemaphore(NULL, 0, 9, "Full");
HANDLE h_semaphore_e = CreateSemaphore(NULL, 9, 9, "Empty");
for ( i = 0; i < (int)(n_thread); i++)
{
if(thread_info[i].command == 'W' || thread_info[1].command == 'w')
{
// Create Writer thread
h_Thread[i] = CreateThread( NULL, 0, (LPTHREAD_START_ROUTINE)(thd_search), &thread_info[i], 0, &thread_ID);
}
else if (thread_info[i].command == 'D' || thread_info[1].command == 'd')
{
// Create Reader thread
h_Thread[i] = CreateThread( NULL, 0, (LPTHREAD_START_ROUTINE)(thd_display), &thread_info[i], 0, &thread_ID);
}
} //end for
// waiting all thread will been finished
wait_for_all = WaitForMultipleObjects(n_thread,h_Thread,TRUE, -1);
printf("All search and display thread have finished Operating.\n");
//output the array at last
printf("The array at last.\n");
for (i=0;i<9;i++)
{
printf(" %d ",prime[i]);
}
printf("\n");
CloseHandle(h_semaphore_f);
CloseHandle(h_semaphore_e);
}// end GetCommand
void thd_display(void* p)
{
//semaphore
HANDLE h_S_Full = OpenSemaphore(SEMAPHORE_ALL_ACCESS, FALSE, "Full");
HANDLE h_S_Empty = OpenSemaphore(SEMAPHORE_ALL_ACCESS, FALSE, "Empty");
//local var
int m_disnum;
int m_serial;
int i,j;
int now_used;
//get info from para
m_serial = ((ThreadInfo*) (p)) -> serial;
m_disnum = ((ThreadInfo*) (p)) -> num_from;
// begin display
for (i=0;i<m_disnum;i++)
{
now_used=GetUsed(prime);
if(searchCount==0 && now_used == 0)
{
break;
}
//wait semaphore
WaitForSingleObject(h_S_Full, INFINITE);
//enter critical section
EnterCriticalSection( &my_section );
printf("Display thread %d begins to output prime num .\n",m_serial);
for (j=0;j<9;j++)
{
if(prime[j]!=0)
{
printf("----------Display thread %d output the prime num \"%d\".\n",m_serial,prime[j]);
prime[j]=0;
break;
}
}
printf("Display thread %d finishes outputting prime num .\n",m_serial);
//leave critical section
LeaveCriticalSection( &my_section );
//release resource
ReleaseSemaphore(h_S_Empty, 1, NULL);
now_used=GetUsed(prime);
if(searchCount==0 && now_used == 0)
{
break;
}
}
//change the count of display thread
CloseHandle(h_S_Full);
CloseHandle(h_S_Empty);
displayCount--;
}
void thd_search(void* p)
{
//semaphore
HANDLE h_S_Full = OpenSemaphore(SEMAPHORE_ALL_ACCESS, FALSE, "Full");
HANDLE h_S_Empty = OpenSemaphore(SEMAPHORE_ALL_ACCESS, FALSE, "Empty");
//local var
DWORD n_from;
DWORD n_to;
int m_serial;
int i,j;
int primenum[100];
int primecount=0;
int now_used;
//get info from para
m_serial = ((ThreadInfo*) (p)) -> serial;
n_from = ((ThreadInfo*) (p)) -> num_from;
n_to = ((ThreadInfo*) (p)) -> num_to;
//get the primenum to write
for (i=n_from;i<= (int) n_to;i++)
{
if(IsPrime(i)==TRUE)
{
primenum[primecount++]=i;
}
}
//begin the search
for (i=0;i<primecount;i++)
{
now_used=GetUsed(prime);
if(displayCount==0 && now_used==9)
{
break;
}
//wait semaphore
WaitForSingleObject(h_S_Empty, INFINITE);
//enter critical section
EnterCriticalSection( &my_section );
printf("Search thread %d begins to write the date .\n",m_serial);
for(j=0;j<9;j++)
{
if (prime[j]==0)
{
prime[j]=primenum[i];
break;
}
}
printf("Search thread %d finish writing the date .\n",m_serial);
//leave critical section
LeaveCriticalSection( &my_section );
//release resource
ReleaseSemaphore(h_S_Full, 1, NULL);
now_used=GetUsed(prime);
if(displayCount==0 && now_used==9)
{
break;
}
}
//change the count of search thread
CloseHandle(h_S_Full);
CloseHandle(h_S_Empty);
searchCount--;
}
任务五 同步对象实现P、V操作
一、基本信息
实践题目:同步对象实现P、V操作
二、实践内容简要描述
实践目标:
用Win32提供的同步对象实现P、V操作,并解决任务4中有限缓冲区问题
实践内容:
用同步对象实现P、V操作解决一下问题:
写一个线程实现C/C++语言程序:一些线程负责找出某个数据范围的素数,并放到一个数组中,另一些线程负责将数组中的素数按次序取出,并显示出来。显示过的数据要从数组中删除。要求定义一个全局变量的数组:int prime[9]用于存放找到的待显示的素数。
三、实践报告主要内容
设计思路:
实现P、V操作用了binary semaphore来实现,
wait操作的实现
Wait(s1);
c--;
if(c<0){
signal(s1);
wait(s2);
}
signal(s1);
signal操作的实现:
wait(s1);
c++;
if(c<=0)
signal(s2);
else
signal(s1);
线程同步仍采用了生产者-消费者算法。
P、V操作用了一个返回值,为0时表示超时,为1表示等待成功。
主要数据结构:
线程信息结构体:
int searchCount = 0; //已开线程数
int displayCount = 0; //已开线程数
CRITICAL_SECTION my_section;
HANDLE h_semaphore_s1_e = CreateSemaphore(NULL, 1, 1, "Bin_S1_Empty"); //Empty的S1
HANDLE h_semaphore_s2_e = CreateSemaphore(NULL, 0, 1, "Bin_S2_Empty"); //Empty的S2
HANDLE h_semaphore_s1_f = CreateSemaphore(NULL, 1, 1, "Bin_S1_Full"); //Full的S1
HANDLE h_semaphore_s2_f = CreateSemaphore(NULL, 0, 1, "Bin_S2_Full"); //Full的S2
int Count_Empty; //Empty计数器
int Count_Full; //Full计数器
struct ThreadInfo
{
int serial;
char command;
int num_from;
int num_to;
};
int prime[9];
void GetCommand( char* file );
void thd_display(void* p);
void thd_search(void* p);
BOOL IsPrime(int num); //用于判断是否为素数
int GetUsed(int num[9]); //用于获得剩余空间
void P(LPCTSTR lpcstr,int &count); //P 操作
void V(LPCTSTR lpcstr,int &count); //V 操作
主要代码分析:
int wait(int *,HANDLE Event[]); // binary semaphore实现的P 操作
int signal(int *,HANDLE Event[]); // binary semaphore实现的V 操作
四、实践结果
基本数据:
源程序代码行数 完成实践投入的总时间 资料查阅时间 编程调试时间 源程序文件
413 1小时 0.5小时 0.5小时 ex5.cpp
测试数据设计:
1.“ex4.dat”文件内容测试结果同ex4:
2.自设测试数据
1 w 10 100
2 w 1 10
3 W 2 20
4 D 20 0
5 D 3 0
测试结果分析:
对应于数据的运行结果:
Reader Priority:
Search thread 1 begins to write the date .
Search thread 1 finish writing the date .
Search thread 1 begins to write the date .
Search thread 1 finish writing the date .
Search thread 1 begins to write the date .
Search thread 1 finish writing the date .
Search thread 1 begins to write the date .
Search thread 1 finish writing the date .
Search thread 2 begins to write the date .
Search thread 2 finish writing the date .
Search thread 3 begins to write the date .
Search thread 3 finish writing the date .
Search thread 2 begins to write the date .
Search thread 2 finish writing the date .
Search thread 3 begins to write the date .
Search thread 3 finish writing the date .
Display thread 4 begins to output prime num .
----------Display thread 4 output the prime num "11".
Display thread 4 finishes outputting prime num .
Display thread 5 begins to output prime num .
----------Display thread 5 output the prime num "13".
Display thread 5 finishes outputting prime num .
Search thread 2 begins to write the date .
Search thread 2 finish writing the date .
Search thread 3 begins to write the date .
Search thread 3 finish writing the date .
Display thread 4 begins to output prime num .
----------Display thread 4 output the prime num "7".
Display thread 4 finishes outputting prime num .
Display thread 5 begins to output prime num .
----------Display thread 5 output the prime num "7".
Display thread 5 finishes outputting prime num .
Search thread 3 begins to write the date .
Search thread 3 finish writing the date .
Display thread 4 begins to output prime num .
----------Display thread 4 output the prime num "11".
Display thread 4 finishes outputting prime num .
Display thread 5 begins to output prime num .
----------Display thread 5 output the prime num "17".
Display thread 5 finishes outputting prime num .
Search thread 1 begins to write the date .
Search thread 1 finish writing the date .
Search thread 3 begins to write the date .
Search thread 3 finish writing the date .
Search thread 1 begins to write the date .
Search thread 1 finish writing the date .
Search thread 3 begins to write the date .
Search thread 3 finish writing the date .
Display thread 4 begins to output prime num .
----------Display thread 4 output the prime num "23".
Display thread 4 finishes outputting prime num .
Search thread 1 begins to write the date .
Search thread 1 finish writing the date .
Display thread 4 begins to output prime num .
----------Display thread 4 output the prime num "31".
Display thread 4 finishes outputting prime num .
Search thread 3 begins to write the date .
Search thread 3 finish writing the date .
Display thread 4 begins to output prime num .
----------Display thread 4 output the prime num "19".
Display thread 4 finishes outputting prime num .
Search thread 1 begins to write the date .
Search thread 1 finish writing the date .
Display thread 4 begins to output prime num .
----------Display thread 4 output the prime num "37".
Display thread 4 finishes outputting prime num .
Search thread 1 begins to write the date .
Search thread 1 finish writing the date .
Display thread 4 begins to output prime num .
----------Display thread 4 output the prime num "41".
Display thread 4 finishes outputting prime num .
Search thread 1 begins to write the date .
Search thread 1 finish writing the date .
Display thread 4 begins to output prime num .
----------Display thread 4 output the prime num "43".
Display thread 4 finishes outputting prime num .
Search thread 1 begins to write the date .
Search thread 1 finish writing the date .
Display thread 4 begins to output prime num .
----------Display thread 4 output the prime num "47".
Display thread 4 finishes outputting prime num .
Search thread 1 begins to write the date .
Search thread 1 finish writing the date .
Display thread 4 begins to output prime num .
----------Display thread 4 output the prime num "53".
Display thread 4 finishes outputting prime num .
Search thread 1 begins to write the date .
Search thread 1 finish writing the date .
Display thread 4 begins to output prime num .
----------Display thread 4 output the prime num "59".
Display thread 4 finishes outputting prime num .
Search thread 1 begins to write the date .
Search thread 1 finish writing the date .
Display thread 4 begins to output prime num .
----------Display thread 4 output the prime num "61".
Display thread 4 finishes outputting prime num .
Search thread 1 begins to write the date .
Search thread 1 finish writing the date .
Display thread 4 begins to output prime num .
----------Display thread 4 output the prime num "67".
Display thread 4 finishes outputting prime num .
Search thread 1 begins to write the date .
Search thread 1 finish writing the date .
Display thread 4 begins to output prime num .
----------Display thread 4 output the prime num "71".
Display thread 4 finishes outputting prime num .
Search thread 1 begins to write the date .
Search thread 1 finish writing the date .
Display thread 4 begins to output prime num .
----------Display thread 4 output the prime num "73".
Display thread 4 finishes outputting prime num .
Search thread 1 begins to write the date .
Search thread 1 finish writing the date .
Display thread 4 begins to output prime num .
----------Display thread 4 output the prime num "79".
Display thread 4 finishes outputting prime num .
Search thread 1 begins to write the date .
Search thread 1 finish writing the date .
Display thread 4 begins to output prime num .
----------Display thread 4 output the prime num "83".
Display thread 4 finishes outputting prime num .
Display thread 4 begins to output prime num .
----------Display thread 4 output the prime num "13".
Display thread 4 finishes outputting prime num .
Display thread 4 begins to output prime num .
----------Display thread 4 output the prime num "29".
Display thread 4 finishes outputting prime num .
Search thread 1 begins to write the date .
Search thread 1 finish writing the date .
Search thread 1 begins to write the date .
Search thread 1 finish writing the date .
All search and display thread have finished Operating.
The array at last.
89 97 0 19 3 3 5 5 17
Press any key to finish this Program.
Thank you test this Program!
程序运行过程中,线程1、线程2、线程3为找素数线程,线程4、线程5负责显示,它们均交叉访问临界区,程序运行结果完全正确。
五、实践体会
该实验与实验四相比,只是用软件的方法来实现内核对象的功能,只须细心就能顺利完成任务。
通过实验我基本了解了P、V操作的具体实现,以及有限缓冲区问题的解决方法。
七、参考文献
1、MSDN
2、《操作系统概念(第六版 影印版)》,Abraham Silberschatz、Peter Baer Galvin、Greg Gagne,
高等教育出版社
附:源程序部分关键代码
void P(LPCTSTR lpcstr,int &count)
{
HANDLE h_s1,h_s2;
if(strcmp(lpcstr,"Empty") == 0)
{
h_s1=OpenSemaphore(SEMAPHORE_ALL_ACCESS,FALSE,"Bin_S1_Empty");
h_s2=OpenSemaphore(SEMAPHORE_ALL_ACCESS,FALSE,"Bin_S2_Empty");
}
else if(strcmp(lpcstr,"Full") == 0)
{
h_s1=OpenSemaphore(SEMAPHORE_ALL_ACCESS,FALSE,"Bin_S1_Full");
h_s2=OpenSemaphore(SEMAPHORE_ALL_ACCESS,FALSE,"Bin_S2_Full");
}
WaitForSingleObject(h_s1, INFINITE);
count--;
if (count < 0)
{
ReleaseSemaphore(h_s1, 1, NULL);
WaitForSingleObject(h_s2, INFINITE);
}
ReleaseSemaphore(h_s1, 1, NULL);
CloseHandle(h_s1);
CloseHandle(h_s2);
}
void V(LPCTSTR lpcstr,int &count)
{
HANDLE h_s1,h_s2;
if(strcmp(lpcstr,"Empty") == 0)
{
h_s1=OpenSemaphore(SEMAPHORE_ALL_ACCESS,FALSE,"Bin_S1_Empty");
h_s2=OpenSemaphore(SEMAPHORE_ALL_ACCESS,FALSE,"Bin_S2_Empty");
}
else if(strcmp(lpcstr,"Full") == 0)
{
h_s1=OpenSemaphore(SEMAPHORE_ALL_ACCESS,FALSE,"Bin_S1_Full");
h_s2=OpenSemaphore(SEMAPHORE_ALL_ACCESS,FALSE,"Bin_S2_Full");
}
WaitForSingleObject(h_s1, INFINITE);
count++;
if (count <= 0)
{
ReleaseSemaphore(h_s2, 1, NULL);
}
else
{
ReleaseSemaphore(h_s1, 1, NULL);
}
CloseHandle(h_s1);
CloseHandle(h_s2);
}
任务六 LINUX下以原生方式查看软盘信息
一、基本信息
实践题目:在LINUX下以原生(raw)方式查看软盘的信息
二、实践内容简要描述
实践目标:
熟悉Linux操作系统下的基本操作及其程序设计的基本方法。
学会在LINUX下使用原生方式查看软盘上的数据信息。
实践内容:
在LINUX下使用原生方式查询并显示目前磁盘的以下信息:
-每扇区字节数
-每磁道扇区数
-每柱面的磁道数(磁头数)
三、实践报告主要内容
设计思路:
只要正确定位文件的读取位置并确定所需读取的字节数便可以正确读取软盘上的数据,先用open函数以只读方式打开软盘,再用lseek定位读取位置,然后用read读取相应字节的数据即可。
主要数据结构:
int fd; //文件描述符
size_t num_read;
int bytes_per_sector = 0; //每扇区字节数
int sectors_per_track = 0; //每磁道扇区数
int number_of_surface = 0; //每柱面的磁道数(磁头数)
int * pi; //指向文件缓冲区的指针
pi = &bytes_per_sector;
pi = §ors_per_track;
pi = &number_of_surface;
主要代码分析: 详见代码注释。
四、实践结果
基本数据:
源程序代码行数 完成实践投入的总时间 资料查阅时间 编程调试时间 源程序文件
43 0.5小时 0.4小时 0.1小时 ex6.cpp
测试数据设计:
3.5寸软盘一张。
测试结果分析:
程序运行结果为:
Bytes per sector: 512
Sectors per track: 18
Number of surfaces:: 2
程序运行结果完全正确。
五、实践体会
以原生方式读取磁盘信息时,将磁盘当作一个文件打开,要正确定位文件的读取位置,并确定读取字节数,这样便能从中读取相应数据。通过实验,了解了软盘上BOOT的布局,并熟悉了Linux操作系统下程序设计的基本方法和基本操作。
六、参考文献
1、《Linux基础教程》,黄庆生 吴振华 苏哲 编著,人民邮电出版社
附:源程序代码
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
int main()
{
//每扇区字节数 0x0b-0x0c 11 - 12
//每磁道扇区数 0x18-0x19 24 - 25
//每柱面的磁道数 0x1a-0x1b 26 – 27
int fd;
size_t num_read;
int bytes_per_sector = 0;
int sectors_per_track = 0;
int number_of_surface = 0;
int * pi;
fd = open("/dev/fd0", O_RDONLY);
pi = &bytes_per_sector;
lseek(fd,(off_t)11,SEEK_SET);
num_read = read(fd,(void *)pi,(size_t)2);
printf("Bytes per sector: %d\n",bytes_per_sector);
pi = §ors_per_track;
lseek(fd,(off_t)24,SEEK_SET);
num_read = read(fd,(void *)pi,(size_t)2);
printf("Sectors per track: %d\n",sectors_per_track);
pi = &number_of_surface;
lseek(fd,(off_t)26,SEEK_SET);
num_read = read(fd,(void *)pi,(size_t)2);
printf("Number of surfaces: %d\n",number_of_surface);
return 0;
}
更多内容:
编译原理实验报告
http://blog.csdn.net/ctu_85/archive/2006/09/09/1198568.aspx
汉语编程企业管理应用软件可行性研究报告
http://blog.csdn.net/ctu_85/archive/2007/01/22/1490139.aspx
汉语编程企业管理应用软件需求说明书
http://blog.csdn.net/ctu_85/archive/2007/01/22/1490136.aspx
铁路售票系统软件可行性报告
http://blog.csdn.net/ctu_85/archive/2006/06/06/775894.aspx
铁路售票系统软件需求分析报告
http://blog.csdn.net/ctu_85/archive/2006/06/06/775892.aspx
三维建筑物图像的二维建模
http://blog.csdn.net/ctu_85/archive/2006/12/20/1451106.aspx
分段线性骨架
http://blog.csdn.net/ctu_85/archive/2006/06/15/799847.aspx
基于图论的图像分割技术
http://blog.csdn.net/ctu_85/archive/2006/06/15/799857.aspx
Linux文件系统
http://blog.csdn.net/ctu_85/archive/2006/06/12/791644.aspx
分层模型
http://blog.csdn.net/ctu_85/archive/2006/06/07/777997.aspx
两种计算Ack(m,n)的非递归算法
http://blog.csdn.net/ctu_85/archive/2006/11/29/1419396.aspx
上海交通大学1999年试题解答
http://blog.csdn.net/ctu_85/archive/2006/11/09/1376289.aspx
东北大学2001年试题解答
http://blog.csdn.net/ctu_85/archive/2006/11/09/1376287.aspx
清华大学1994年试题解答
http://blog.csdn.net/ctu_85/archive/2006/10/24/1349754.aspx
中国科学院2002年试题解答
http://blog.csdn.net/ctu_85/archive/2006/10/24/1349704.aspx
浙江大学计算机复试解答1
http://blog.csdn.net/ctu_85/archive/2006/10/15/1334936.aspx
浙江大学计算机复试解答2
http://blog.csdn.net/ctu_85/archive/2006/10/16/1336101.aspx
浙江大学计算机复试解答3
http://blog.csdn.net/ctu_85/archive/2006/11/02/1363159.aspx