实验一 类Windows进程任务管理器实验
一、课程设计(综合实验)的目的与要求
- 实验目的
理解Windows编程环境下的进程管理机制,能创建一个完成特定功能的进程,并能对进程进行信息的获取、终止和保护,实现一个类Windows的进程任务管理器。
- 实验要求
程序可为控制台或带界面应用程序,要求有较好的用户体验,完成功能:
-
- 能够完成创建进程的功能,打印输出新建进程ID。
- 获取当前系统进程信息,列出可选显示进程信息项,根据选择显示输出进程信息。
- 终止任意进程并获取退出代码。
- 具体实现技术不限。
二、设计(实验)正文
- 程序主要由三部分组成:创建进程、获取进程信息、终止进程
- 创建进程函数
首先定义要启动的可执行文件路径,然后用CreateProcess()函数创建并启动进程。若创建进程失败,则输出failed,若创建成功则输出新进程ID,最后关闭句柄。
- 获取进程信息函数
首先通过Win32 API函数CreateToolhelp32Snapshot()获取系统快照,并通过函数Process32First()和Procee32Next()获取系统快照中第一个和下一个系统的信息,依次输出进程名称、进程ID、父进程ID,最后关闭句柄
- 终止进程函数
首先输入要终止函数的ID,打开该进程,然后通过TerminateProcess()函数终止进程,最后关闭句柄。
- 主函数
在主函数中用switch函数实现通过输入数字选择要使用的功能。
三、课程设计(综合实验)总结或结论
刚开始设计时感到无从下手,通过查阅资料和理解相关函数调用后,一步步实现了实验要求的功能。通过这个实验,我对进程的了解更加深入,并且学会了如何用代码实现创建进程、获取进程信息和终止进程。
四、参考文献
附录(设计流程图、程序、表格、数据等)
注:根据课程设计、综合实验的内容将标题任选其一。
#include <iostream>
#include <windows.h>
#include <tlhelp32.h>
#include <string>
using namespace std;
// 创建进程函数
void createProcess() {
STARTUPINFO si;
PROCESS_INFORMATION pi;
ZeroMemory(&si, sizeof(si));
si.cb = sizeof(si);
ZeroMemory(&pi, sizeof(pi));
// 要启动的可执行文件路径
TCHAR* appName = TEXT("notepad.exe");
// 启动进程
if (!CreateProcess(NULL, appName, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi)) {
cout << "Error: Create Process failed" << endl;
return;
}
// 输出新建进程ID
cout << "New process created: " << pi.dwProcessId << endl;
// 关闭句柄
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
}
// 获取进程信息函数
void getProcessInfo() {
DWORD pid = 0;
PROCESSENTRY32 pe32 = { 0 };
pe32.dwSize = sizeof(PROCESSENTRY32);
// 列举系统中所有进程
HANDLE hProcessSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
if (Process32First(hProcessSnap, &pe32)) {
cout << "Process list:" << endl;
do {
cout << "Process name: " << pe32.szExeFile << endl;
cout << "Process ID: " << pe32.th32ProcessID << endl;
cout << "Parent process ID: " << pe32.th32ParentProcessID << endl;
cout << "---------------------------------------" << endl;
} while (Process32Next(hProcessSnap, &pe32));
}
// 关闭句柄
CloseHandle(hProcessSnap);
}
// 终止进程函数
void terminateProcess() {
DWORD pid;
cout << "Please input the PID of the process you want to terminate: ";
cin >> pid;
// 打开进程
HANDLE hProcess = OpenProcess(PROCESS_TERMINATE, FALSE, pid);
if (hProcess == NULL) {
cout << "Error: Open Process failed" << endl;
return;
}
// 终止进程
if (!TerminateProcess(hProcess, 0)) {
cout << "Error: Terminate Process failed" << endl;
}
else {
cout << "Process terminated successfully." << endl;
}
// 关闭句柄
CloseHandle(hProcess);
}
int main() {
int option;
do {
cout << "===========================" << endl;
cout << "Please select an option:" << endl;
cout << "1. Create process" << endl;
cout << "2. Get process information" << endl;
cout << "3. Terminate process" << endl;
cout << "4. Exit" << endl;
cout << "===========================" << endl;
cin >> option;
switch (option) {
case 1:
createProcess();
break;
case 2:
getProcessInfo();
break;
case 3:
terminateProcess();
break;
default:
cout << "Invalid option." << endl;
break;
}
} while (option != 4);
}
实验二 用多线程同步方法解决哲学家就餐问题
一、课程设计(综合实验)的目的与要求
- 实验目的
理解Windows编程环境下的线程同步机制,掌握线程同步的方法,包括临界区对象、事件内核对象、互锁函数等方法,并能用线程同步解决经典的线程同步问题,体会多线程编程。
- 实验要求
- 为每个哲学家产生一个线程,设计正确的同步算法
- 每个哲学家取得一双筷子开始用餐后,即时显示“Dining…”和该哲学家的自定义标识符以及餐桌上所有几位哲学家标识符及其所坐的位置。
- 设定共有5个哲学家需用餐。每位用餐耗时10秒钟以上。
- 多个哲学家须共享操作函数代码
-
- 最好有界面展示。
二、设计(实验)正文
- 如果让所有哲学家都先拿起左边筷子再拿起右边筷子,则可能会产生死锁。所以在程序中规定每个哲学家拿筷子的顺序:编号为奇数的哲学家先拿右边筷子,再拿左边筷子,编号为偶数的哲学家先拿左边的筷子,再拿右边的筷子。
- 在循环中,先让哲学家思考一会,然后分别让编号为奇偶数的哲学家用lock函数锁住对应的筷子,并同时锁住输出信息防止输出信息被打断。当哲学家同时锁住两根筷子时,输出dinnering。用餐一段时间后,将哲学家的两根筷子解锁。
三、课程设计(综合实验)总结或结论
通过哲学家进餐问题实验,我对多线程同步机制的理解更加深刻,并学会了用进程同步方法解决问题,理解了临界区对象、时间内核对象和书多函数等方法。
四、参考文献
附录(设计流程图、程序、表格、数据等)
注:根据课程设计、综合实验的内容将标题任选其一。
#include <iostream>
#include <thread>
#include <mutex>
using namespace std;
const int kNumPhilosophers = 5;
mutex cho[kNumPhilosophers]; // 用于锁住每一对筷子的互斥锁
mutex ioMutex; // 用于锁住输出信息的互斥锁
// 模拟哲学家的行为,id为哲学家编号
void philosopher(int id) {
int left = id;
int right = (id + 1) % kNumPhilosophers;
while (true) {
// 哲学家思考一会儿
this_thread::sleep_for(chrono::milliseconds(1000 + rand() % 1000));
if (id % 2 == 0) {
// 尝试锁住左边的筷子
cho[left].lock();
{
lock_guard<mutex> lock(ioMutex); // 为了避免输出信息被打断,需要在输出前先获得输出互斥锁
cout << "Philosopher " << id << " picks up left cho " << left << endl;
}
// 尝试锁住右边的筷子
cho[right].lock();
{
lock_guard<mutex> lock(ioMutex);
cout << "Philosopher " << id << " picks up right cho " << right << endl;
cout << "Philosopher " << id << " is Dining... with chos " << left << " and " << right << endl;
// 输出哲学家和其它哲学家的信息
for (int i = 0; i < kNumPhilosophers; ++i) {
if (i != id) {
cout << "Philosopher " << i << " is ";
if (cho[i].try_lock()) {
cout << "holding cho " << i << endl;
cho[i].unlock();
}
else {
cout << "not holding cho " << i << endl;
}
}
}
}
}
if (id % 2 == 1) {
// 尝试锁住右边的筷子
cho[right].lock();
{
lock_guard<mutex> lock(ioMutex); // 为了避免输出信息被打断,需要在输出前先获得输出互斥锁
cout << "Philosopher " << id << " picks up right cho " << right << endl;
}
// 尝试锁住左边的筷子
cho[left].lock();
{
lock_guard<mutex> lock(ioMutex);
cout << "Philosopher " << id << " picks up left cho " << left << endl;
cout << "Philosopher " << id << " is Dining... with chos " << left << " and " << right << endl;
// 输出哲学家和其它哲学家的信息
for (int i = 0; i < kNumPhilosophers; ++i) {
if (i != id) {
cout << "Philosopher " << i << " is ";
if (cho[i].try_lock()) {
cout << "holding cho " << i << endl;
cho[i].unlock();
}
else {
cout << "not holding cho " << i << endl;
}
}
}
}
}
// 用餐一段时间
this_thread::sleep_for(chrono::milliseconds(10000 + rand() % 10000));
cho[left].unlock();
cho[right].unlock();
}
}
int main() {
srand(time(nullptr));
thread philosophers[kNumPhilosophers];
for (int i = 0; i < kNumPhilosophers; ++i) {
philosophers[i] = thread(philosopher, i);
}
for (int i = 0; i < kNumPhilosophers; ++i) {
philosophers[i].join();
}
return 0;
}
实验三 简易绘图器
一、课程设计(综合实验)的目的与要求
- 实验目的
该实验为综合实验,通过该实验,使学生学习使用visual c++进行简单的综合功能的系统开发。巩固Windows编程的基础知识,增加学生的利用图形子环境编程的综合能力,包括界面设计能力、使用GDI,GDI+或WPF的能力等。
- 实验要求
- 利用GDI,GDI+或WPF实现简单绘图器,选其中一种即可,编程环境不限。
- 实现绘制线条、矩形、圆形,可改变线条或填充的颜色。
二、设计(实验)正文
- 选择用WPF语言来实现简易绘图器。程序分为四部分实现四个功能:画矩形,画圆形,画线条,清空画布
- 首先定义画布,在画布上实现绘制图形的功能。在.xmal文件中定义四个按钮,来实现四个功能的切换,并为按钮添加内部逻辑。
- 在.cs文件中先初始化,再定义DrawingCanvas_MouseMove()和DrawingCanvas_MouseMove()函数来实现图形的绘制,用if函数分别当ShapeType等于矩形或圆形或线条时实现不同功能。
- 分别用四个Button_Click函数与图形界面上的四个按钮联系起来,当矩形或圆形或线条按钮被点击时,currentShapeType分别被定义为矩形或圆形或线条。当清空按钮被点击时,清空画布。
三、课程设计(综合实验)总结或结论
简易绘图器实验是一个较为综合的实验,包括界面设计和内部逻辑。通过查阅资料了解了WPF语言的使用方法,和实现绘制矩形、圆形和线条的方法。认识了画布的使用。
但在实验中没有实现改变线条颜色的功能。在查阅资料时,发现了使用ColorPicker等来改变颜色,但实际使用时,显示WPF语言不支持这些方法,还没有找到解决方法来实现改变线条颜色的功能。
四、参考文献
附录(设计流程图、程序、表格、数据等)
注:根据课程设计、综合实验的内容将标题任选其一。
程序分两部分,分为.xaml文件和.cs文件
1、.xaml文件部分
<Window x:Class="WpfApp4.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:WpfApp4"
mc:Ignorable="d"
Title="WPF简易绘图器" Height="450" Width="800">
<Grid>
<Canvas x:Name="drawingCanvas"
Background="White"
MouseDown="DrawingCanvas_MouseDown"
MouseMove="DrawingCanvas_MouseMove"
MouseUp="DrawingCanvas_MouseUp" />
<StackPanel Orientation="Horizontal"
HorizontalAlignment="Left"
VerticalAlignment="Top"
Margin="10">
<Button x:Name="rectangleButton"
Content="Rectangle"
Width="75"
Height="30"
Click="RectangleButton_Click" />
<Button x:Name="ellipseButton"
Content="Ellipse"
Width="75"
Height="30"
Click="EllipseButton_Click" />
<Button x:Name="LineButton"
Content="Line"
Width="75"
Height="30"
Click="LineButton_Click" />
<Button x:Name="ClearButton"
Content="Clear"
Width="75"
Height="30"
Click="ClearButton_Click" />
</StackPanel>
</Grid>
</Window>
2、.cs文件部分
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
namespace WpfApp4
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public enum ShapeType { None, Rectangle, Ellipse, Line };
public partial class MainWindow : Window
{
private Point startPoint;
private Rectangle currentRectangle;
private ShapeType currentShapeType;
private Ellipse currentEllipse;
private Polyline currentPolyline;
public MainWindow()
{
InitializeComponent();
currentShapeType = ShapeType.None;
}
private void DrawingCanvas_MouseDown(object sender, MouseButtonEventArgs e)
{
startPoint = e.GetPosition(drawingCanvas);
if (currentShapeType == ShapeType.Rectangle)
{
currentRectangle = new Rectangle
{
Stroke = Brushes.Black,
StrokeThickness = 1,
Fill = Brushes.LightYellow
};
Canvas.SetLeft(currentRectangle, startPoint.X);
Canvas.SetTop(currentRectangle, startPoint.Y);
drawingCanvas.Children.Add(currentRectangle);
}
else if (currentShapeType == ShapeType.Ellipse)
{
currentEllipse = new Ellipse
{
Stroke = Brushes.Black,
StrokeThickness = 1,
Fill = Brushes.LightBlue
};
Canvas.SetLeft(currentEllipse, startPoint.X);
Canvas.SetTop(currentEllipse, startPoint.Y);
drawingCanvas.Children.Add(currentEllipse);
}
else if (currentShapeType == ShapeType.Line)
{
currentPolyline = new Polyline
{
Stroke = Brushes.Black,
StrokeThickness = 2
};
drawingCanvas.Children.Add(currentPolyline);
}
}
private void DrawingCanvas_MouseMove(object sender, MouseEventArgs e)
{
if (e.LeftButton == MouseButtonState.Pressed && currentShapeType == ShapeType.Rectangle)
{
double x = startPoint.X < e.GetPosition(drawingCanvas).X ? startPoint.X : e.GetPosition(drawingCanvas).X;
double y = startPoint.Y < e.GetPosition(drawingCanvas).Y ? startPoint.Y : e.GetPosition(drawingCanvas).Y;
double width = Math.Abs(startPoint.X - e.GetPosition(drawingCanvas).X);
double height = Math.Abs(startPoint.Y - e.GetPosition(drawingCanvas).Y);
currentRectangle.Width = width;
currentRectangle.Height = height;
Canvas.SetLeft(currentRectangle, x);
Canvas.SetTop(currentRectangle, y);
}
else if (e.LeftButton == MouseButtonState.Pressed && currentShapeType == ShapeType.Ellipse)
{
double x = startPoint.X < e.GetPosition(drawingCanvas).X ? startPoint.X : e.GetPosition(drawingCanvas).X;
double y = startPoint.Y < e.GetPosition(drawingCanvas).Y ? startPoint.Y : e.GetPosition(drawingCanvas).Y;
double width = Math.Abs(startPoint.X - e.GetPosition(drawingCanvas).X);
double height = Math.Abs(startPoint.Y - e.GetPosition(drawingCanvas).Y);
currentEllipse.Width = width;
currentEllipse.Height = height;
Canvas.SetLeft(currentEllipse, x);
Canvas.SetTop(currentEllipse, y);
}
else if (e.LeftButton == MouseButtonState.Pressed && currentShapeType == ShapeType.Line)
{
currentPolyline.Points.Add(e.GetPosition(drawingCanvas));
}
}
private void DrawingCanvas_MouseUp(object sender, MouseButtonEventArgs e)
{
if (currentShapeType == ShapeType.Rectangle)
{
// currentShapeType = ShapeType.None; //是否连续画正方形
}
else if (currentShapeType == ShapeType.Ellipse)
{
// currentShapeType = ShapeType.None; //是否连续画圆形
}
else if (currentShapeType == ShapeType.Line)
{
// currentShapeType = ShapeType.None;
}
}
private void RectangleButton_Click(object sender, RoutedEventArgs e)
{
currentShapeType = ShapeType.Rectangle;
}
private void EllipseButton_Click(object sender, RoutedEventArgs e)
{
currentShapeType = ShapeType.Ellipse;
}
private void LineButton_Click(object sender, RoutedEventArgs e)
{
currentShapeType = ShapeType.Line;
}
private void ClearButton_Click(object sender, RoutedEventArgs e)
{
Canvas canvas = drawingCanvas;
UIElementCollection children = canvas.Children;
canvas.Children.Clear();
}
}
}