实验一:Windows API函数
一:实验要求
- 请在代码中你认为重要处加上注释。
- 除了粘贴代码外,请用专门的文字对程序的设计做简要介绍。
- 如果你在做这个程序的过程中遇到了困难、走了弯路,请一一列出,并说明导致问题的原因,以及你最终的解决办法。
二:实验的工程目标
- 熟悉Windows API函数文档的结构、风格;掌握Windows API的调用方法。
- 仔细阅读API函数的文档,确保缓冲区大小参数的正确有效。必要时对返回值进行检查。
- 编写代码获得当前用户名(GetUserName)、系统目录(GetSystemDirectory)、Windows所在目录(GetWindowsDirectory)、环境变量PATH的值等信息(ExpandEnvironmentStrings)。
- 选作:编写代码获得操作系统的版本信息(GetVersionEx)。
三:实验代码
#include <cstdio>
#include <windows.h>
#include <Lmcons.h>
int main() {
char computer_name_buffer[MAX_COMPUTERNAME_LENGTH + 1];
DWORD computer_name_buffer_size = MAX_COMPUTERNAME_LENGTH + 1;
GetComputerNameA(computer_name_buffer, &computer_name_buffer_size);
printf("ComputerName:%s\n", computer_name_buffer);
char user_name_buffer[UNLEN + 1];
DWORD user_name_buffer_size = UNLEN + 1;
GetUserNameA(user_name_buffer, &user_name_buffer_size);
printf("UserName:%s\n", user_name_buffer);
char system_directory_buffer[1000];
GetSystemDirectoryA(system_directory_buffer, 1000);
printf("SystemDirectory:%s\n", system_directory_buffer);
char windows_directory_buffer[MAX_PATH];
GetWindowsDirectoryA(windows_directory_buffer, MAX_PATH);
printf("WindowsDirectory%s\n", windows_directory_buffer);
const char *environment_string = "%path%";
char environment_string_expanded[10000];
ExpandEnvironmentStringsA(environment_string, environment_string_expanded, 10000);
printf("EnvironmentPath:%s\n", environment_string_expanded);
OSVERSIONINFO version;
ZeroMemory(&version, sizeof(OSVERSIONINFO));
version.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
GetVersionEx(&version);
printf("Version:%d.%d %s\n", version.dwMajorVersion, version.dwMinorVersion, version.szCSDVersion);
return 0;
}
四:实验结果
![Windows API实验结果](https://img-blog.csdnimg.cn/img_convert/63ca61b607ce2075078f1b77f3825696.png#clientId=u0e8940c2-faf6-4&from=paste&height=401&id=u9fa32c6b&originHeight=401&originWidth=983&originalType=binary&ratio=1&rotation=0&showTitle=true&size=78227&status=done&style=none&taskId=ub40bd4c0-70ee-41ae-844e-b82a84eb72a&title=Windows API实验结果&width=983 “Windows API实验结果”)
实验二:线程与互斥
一:实验要求
- 请在代码中你认为重要处加上注释。
- 除了粘贴代码外,请用专门的文字对程序的设计做简要介绍。
- 如果你在做这个程序的过程中遇到了困难、走了弯路,请一一列出,并说明导致问题的原因,以及你最终的解决办法
二:实验的工程目标
- 改写money的代码,用“高级锁”即信号量代替“低级锁”,并感受二者的性能差异。如果可以,请用clock函数测量这种差异(选作)。还可以比较使用多线程与单线程的性能差异(选作)。
- 提示:此处信号量代表什么资源?对全局变量money的访问权就是一种资源,这种资源的数量为1。
三:实验代码
#include <windows.h>
#include <iostream>
#include <ctime>
using namespace std;
int money = 0;
CRITICAL_SECTION lock;
DWORD WINAPI dad(LPVOID) {
EnterCriticalSection(&lock);
for (int i = 0; i < 100000; i++) {
money++;
}
LeaveCriticalSection(&lock);
return 0;
}
DWORD WINAPI mom(LPVOID) {
EnterCriticalSection(&lock);
for (int i = 0; i < 100000; i++) {
money++;
}
LeaveCriticalSection(&lock);
return 0;
}
DWORD WINAPI oth(LPVOID) {
EnterCriticalSection(&lock);
for (int i = 0; i < 100000; i++) {
money++;
}
LeaveCriticalSection(&lock);
return 0;
}
int main() {
clock_t start, middle, finish;
double Times;
start = clock();
HANDLE thread_dad;
HANDLE thread_mom;
HANDLE thread_oth;
InitializeCriticalSection(&lock);
thread_dad = CreateThread(nullptr, 0, dad, nullptr, 0, nullptr);
thread_mom = CreateThread(nullptr, 0, mom, nullptr, 0, nullptr);
thread_oth = CreateThread(nullptr, 0, oth, nullptr, 0, nullptr);
middle = clock();
Times = (double) (middle - start) / CLOCKS_PER_SEC;
cout << "低级锁运行时间(秒): " << Times << endl;
WaitForSingleObject(thread_dad, INFINITE);
WaitForSingleObject(thread_mom, INFINITE);
WaitForSingleObject(thread_oth, INFINITE);
DeleteCriticalSection(&lock);
finish = clock();
Times = (double) (finish - middle) / CLOCKS_PER_SEC;
cout << "高级锁运行时间(秒): " << Times << endl;
return 0;
}
四:实验结果
实验三:页置换模拟
一:实验要求
- 请在代码中你认为重要处加上注释。
- 除了粘贴代码外,请用专门的文字对程序的设计做简要介绍。
- 如果你在做这个程序的过程中遇到了困难、走了弯路,请一一列出,并说明导致问题的原因,以及你最终的解决办法。
二:实验的工程目标
- 给定一个页面访问的轨迹,程序模拟先进先出置换算法下操作系统的行为。
- 参考FIFO置换算法的模拟程序,实现LRU算法的模拟程序。
- 选作:加上一列显示调出页;修复程序的bug(提示:FIFOQueue数组元素为0时,是表示没东西)
- 考虑下述页面走向:1,2,3,4,2,1,5,6,2,1,2,3,7,6,3,2,1,2,3,6,当内存块数量分别为3时,试问FIFO、LRU置换算法的缺页次数各是多少?
三:实验代码
#include <cstdio>
const int MemCapacity = 3;
int FIFOQueue[MemCapacity] = {0};
int exit_page = 0;
int pageInMainMem(int page) {
for (int i = 0; i < MemCapacity; i++) {
if (FIFOQueue[i] == page)
return i;
}
return -1;
}
void foldPage(int page) {
for (int i = MemCapacity - 1; i > 0; i--)
FIFOQueue[i] = FIFOQueue[i - 1];
FIFOQueue[0] = page;
}
int main() {
int pageFootprints[] = {1, 2, 3, 4, 2, 1, 5, 6, 2, 1, 2, 3, 7, 6, 3, 2, 1, 2, 3, 6};
int pageNum = sizeof pageFootprints / sizeof pageFootprints[0];
int RequestCount = 0;
bool request;
printf("时刻\t访问页面\t主存状态\t缺页中断\t调入页\t调出页\n");
for (int i = 0; i < pageNum; i++) {
printf("%3d\t %2d\t ", i, pageFootprints[i]);
request = false;
if (pageInMainMem(pageFootprints[i]) == -1) {
if (FIFOQueue[MemCapacity - 1] != 0) {
exit_page = FIFOQueue[MemCapacity - 1];
}
foldPage(pageFootprints[i]);
RequestCount++;
request = true;
}
for (int j: FIFOQueue)
printf("%2d ", j);
if (request) {
printf("\t\t+");
printf("\t %d", pageFootprints[i]);
if (exit_page != 0) {
printf("\t %d", exit_page);
}
}
printf("\n");
}
printf("缺页中断次数 = %d\n", RequestCount);
printf("缺页率 = %d/%d = %.2f%%\n", RequestCount, pageNum, (float) RequestCount / (float) pageNum * 100);
return 0;
}
四:实验结果
实验四:创建进程
一:实验要求
- 请在代码中你认为重要处加上注释。
- 除了粘贴代码外,请用专门的文字对程序的设计做简要介绍。
- 如果你在做这个程序的过程中遇到了困难、走了弯路,请一一列出,并说明导致问题的原因,以及你最终的解决办法。
二:实验的工程目标
使用CreateProcess函数创建新的进程。程序中创建新的进程,新进程执行记事本的可执行文件打开记事本,主进程休眠,等待记事本进程结束。用户关闭记事本后,WinMain函数中的主进程关闭进程句柄后结束。
三:实验代码
#include <windows.h>
int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) {
TCHAR sCommandLine[1000];
BOOL ret;
DWORD dwExitCode;
PROCESS_INFORMATION pi;
STARTUPINFO si = {sizeof(si)};
//得到Windows目录
GetWindowsDirectory(sCommandLine, MAX_PATH);
//启动"记事本"程序的命令行
strcat(sCommandLine, "\\notepad.exe");
// 启动"记事本"作为子进程
ret = CreateProcess(nullptr, sCommandLine, nullptr, nullptr, FALSE, 0, nullptr, nullptr, &si, &pi);
if (ret) {
CloseHandle(pi.hThread);
//关闭子进程的主线程句柄
WaitForSingleObject(pi.hProcess, INFINITE);
//等待子进程的退出
GetExitCodeProcess(pi.hProcess, &dwExitCode);
//获取子进程的退出码
CloseHandle(pi.hProcess);
//关闭子进程句柄
}
return 0;
}
四:实验结果
实验五:进程中启动计算器子程序
一:实验要求
- 请在代码中你认为重要处加上注释。
- 除了粘贴代码外,请用专门的文字对程序的设计做简要介绍。
- 如果你在做这个程序的过程中遇到了困难、走了弯路,请一一列出,并说明导致问题的原因,以及你最终的解决办法。
二:实验的工程目标
用程序实现启动一个新的进程,并在进程中启动计算器应用程序(calc.exe)。
三:实验代码
#include<windows.h>
#include<cstdio>
int main() {
char path[10] = "calc.exe";
DWORD dwExitCode;
PROCESS_INFORMATION pi;
DWORD ret;
STARTUPINFO si = {sizeof(si)};
ret = CreateProcess(nullptr, path, nullptr, nullptr, FALSE, 0, nullptr, nullptr, &si, &pi);
if (ret) {
WaitForSingleObject(pi.hProcess, INFINITE);
CloseHandle(pi.hThread);
GetExitCodeProcess(pi.hProcess, &dwExitCode);
CloseHandle(pi.hProcess);
}
printf("\n进程结束,退出码是 %ld\n", ret);
return 0;
}
四:实验结果
实验六:建立线程(一个线程,主线程不休眠)
一:实验要求
- 请在代码中你认为重要处加上注释。
- 除了粘贴代码外,请用专门的文字对程序的设计做简要介绍。
- 如果你在做这个程序的过程中遇到了困难、走了弯路,请一一列出,并说明导致问题的原因,以及你最终的解决办法。
二:实验的工程目标
程序演示使用函数_beginthreadex启动线程。
三:实验代码
#include <cstdio>
#include <windows.h>
#include <process.h>
unsigned int WINAPI Fun(LPVOID lpParamter) {
while (true) {
printf("---Fun display!\n");
Sleep(500);//休眠0.5s
}
return 0;
}
int main() {
HANDLE hThread;
hThread = (HANDLE) _beginthreadex(nullptr, 0, Fun, nullptr, 0, nullptr);//创建线程,执行Fun函数
while (true) {
printf("main display!\n");
Sleep(500);//休眠0.5s
}
CloseHandle(hThread);//关闭句柄
return 0;
}