?? 設計報告.txt
字號:
任務一 實現批處理
一、基本信息
實踐題目:實現批處理
二、實踐內容簡要描述
實踐目標:
(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
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -