操作系统实验

  1. 1. 1.列举系统启动进程
  2. 2. 2. 进程管理实验
  3. 3. 3. 进程、互斥同步实验
  4. 4. 4. 共享内存实验
  5. 5. 5. 操作系统系统接口实验

1.列举系统启动进程

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
列举系统启动进程
#include "stdafx.h"
#include "windows.h"
#include "stdio.h"
#include "Tlhelp32.h"


int main(int argc, char* argv[])
{
HANDLE Snapshot;
DWORD m_ProcessIndex[50];//存放所有进程的ID
Snapshot=CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS,0);
//获得某一时刻系统的进程、堆(heap)、模块(module)或线程的快照信息
PROCESSENTRY32 processListStr;
processListStr.dwSize=sizeof(PROCESSENTRY32);
BOOL return_value;
return_value=Process32First(Snapshot,&processListStr);
//获得系统进程链表中第一个进程的信息

int i=0;//item index
while(return_value)
{
printf("ExeFile=%s ",processListStr.szExeFile);
printf("cntThreads=%d ",processListStr.cntThreads);
printf("ParentProcessID=%d ",processListStr.th32ParentProcessID);
printf("ProcessID=%d ",processListStr.th32ProcessID);
printf("PriClassBase=%d\n",processListStr.pcPriClassBase);
int memory=processListStr.cntThreads;
m_ProcessIndex[i]=processListStr.th32ProcessID;//save ID into array to teminate
return_value=Process32Next(Snapshot,&processListStr);
//获得系统进程链表中下一个进程的信息
i++;
}
return 0;
}
typedef struct tagPROCESSENTRY32
{
DWORD dwSize;
DWORD cntUsage;
DWORD th32ProcessID; // this process
DWORD th32DefaultHeapID;
DWORD th32ModuleID; // associated exe
DWORD cntThreads;
DWORD th32ParentProcessID; // this process's parent process
LONG pcPriClassBase; // Base priority of process's threads
DWORD dwFlags;
CHAR szExeFile[MAX_PATH]; // Path
} PROCESSENTRY32;
关闭进程
HANDLE ProcessHandle;
ProcessHandle=OpenProcess(PROCESS_ALL_ACCESS,FALSE,ProcessId);
//利用数组ID指定的获得存在的一个进程的句柄
if(ProcessHandle)
{TerminateProcess(ProcessHandle,0);
}

2. 进程管理实验

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
实验一  进程管理实验
一、实验环境
Windows 2000,VC++ 6.0。
二、实验目的
1、自己设计程序实现Windows系统中进程的创建、中止等操作;
2、设计一个程序能显示当前Windows系统中的所有进程,及进程的进程名、进程号、父进程号、进程优先级等信息,并分析这些信息之间的关系。
三、实验原理
进程的创建通过CreateProcess()函数来实现,CreateProcess()通过创建一个新的进程及在其地址空间内运行的主线程来启动并运行一个新的程序。具体的,在执行CreateProcess()函数时,首先由操作系统负责创建一个进程内核对象,初始化计数为1,并立即为新进程创建一块虚拟地址空间。随后将可执行文件或其他任何必要的动态链接库文件的代码和数据装载到该地址空间中。在创建主线程时,也是首先由系统负责创建一个线程内核对象,并初始化为1。最后启动主线程并执行进程的入口函数WinMain(),完成对进程和执行线程的创建。
CreateProcess()函数的原型声明如下:
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 // 指向进程信息结构的指针
);
显示当前Windows系统中的所有进程原理,系统中有个进程链表,用来保存当前运行的所有进程的信息,程序首先调用函数CreateToolhelp32Snapshot获得进程链表的句柄,然后调用函数ProcessFirst和ProcessNext获得进程结构PROCESSENTRY32,进程的信息都包括在其中。终止一个进程,首先调用OpenProcess函数获得指定函数的句柄,然后调用函数TerminateProcess使指定进程结束。
HANDLE WINAPI CreateToolhelp32Snapshot(DWORD dwFlags,DWORD th32ProcessID);
功能:获得某一时刻系统中由dwFlags标识的进程、堆(heap)、模块(module)或线程的快照信息。
参数说明:
dwFlags:指明返回的是哪一种快照的句柄。
Th32ProcessID:当取TH32CS_SNAPHEAPLIST和TH32CS_SNAPMODULE时才有用。
HANDLE OpenProcess(DWORD dwDesiredAccess,BOOL bInheritHandle,
DWORD dwProcessId);
功能:返回指定进程的句柄。
参数说明:
dwDesiredAccess:指定对指定进程的操作。
bInheritHandle:指明返回的句柄是否能被继承。
dwProcessId:指定要打开的进程的ID。
BOOL WINAPI Process32First(HANDLE hSnapshot, LPPROCESSENTRY32 lppe);
功能:获得系统进程链表中第一个进程的信息。
参数说明:
hSnapshot:调用获得的CreateToolhelp32Snapshot快照句柄。
lppe:指向PROCESSENTRY32进程结构,该结构保存有该进程的相关信息。
BOOL WINAPI Process32Next(HANDLE hSnapshot, LPPROCESSENTRY32 lppe);
功能:获得系统进程链表中下一个进程的信息。
typedef struct tagPROCESSENTRY32
{
DWORD dwSize;
DWORD cntUsage;
DWORD th32ProcessID; // this process
DWORD th32DefaultHeapID;
DWORD th32ModuleID; // associated exe
DWORD cntThreads;
DWORD th32ParentProcessID; // this process's parent process
LONG pcPriClassBase; // Base priority of process's threads
DWORD dwFlags;
CHAR szExeFile[MAX_PATH]; // Path
} PROCESSENTRY32;
四、实验步骤
(1)画出程序流程图
(2)编写程序源代码
创建子进程
#include "stdafx.h"
#include "windows.h"
#include "stdio.h"
int main(int argc, char* argv[])
{
STARTUPINFO si;
PROCESS_INFORMATION pi;
DWORD processId;

processId=GetCurrentProcessId();
printf("CurrentProcessId is:%d\n",processId);
ZeroMemory( &si, sizeof(si) );
si.cb = sizeof(si);
ZeroMemory( &pi, sizeof(pi) );
if(
!CreateProcess( NULL,//No module name (use command line).
"c:\\windows\\Notepad.exe",
//"proctest", // Command line.
NULL, // Process handle not inheritable.
NULL, // Thread handle not inheritable.
FALSE, // Set handle inheritance to FALSE.
0, // No creation flags.
NULL, // Use parent's environment block.
NULL, // Use parent's starting directory.
&si, // Pointer to STARTUPINFO structure.
&pi ) // Pointer to PROCESS_INFORMATION structure.
)
{
//ErrorExit( "CreateProcess failed." );
printf("CreateProcess failed.\n");
}
// Wait until child process exits.
WaitForSingleObject( pi.hProcess, INFINITE );
// Close process and thread handles.
CloseHandle( pi.hProcess );
CloseHandle( pi.hThread );
//TerminateProcess(pi.hProcess,0);
return 0;
}
列举系统中所有进程及相关信息
#include "stdafx.h"
#include "windows.h"
#include "stdio.h"
#include "Tlhelp32.h"

int main(int argc, char* argv[])
{
HANDLE Snapshot;
DWORD m_ProcessIndex[50];//存放所有进程的ID
Snapshot=CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS,0);
//获得某一时刻系统的进程、堆(heap)、模块(module)或线程的快照信息
PROCESSENTRY32 processListStr;
processListStr.dwSize=sizeof(PROCESSENTRY32);
BOOL return_value;
return_value=Process32First(Snapshot,&processListStr);
//获得系统进程链表中第一个进程的信息

int i=0;//item index
while(return_value){
printf("ExeFile=%s ",processListStr.szExeFile);
printf("cntThreads=%d ",processListStr.cntThreads);
printf("PPID=%d ",processListStr.th32ParentProcessID);
printf("PID=%d ",processListStr.th32ProcessID);
printf("PriClassBase=%d\n",processListStr.pcPriClassBase);
int memory=processListStr.cntThreads;
m_ProcessIndex[i]=processListStr.th32ProcessID;//save ID into array to teminate
return_value=Process32Next(Snapshot,&processListStr);
//获得系统进程链表中下一个进程的信息
i++;
}

return 0;
}
(3)源程序编译运行
五、实验结果及分析

3. 进程、互斥同步实验

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
实验二(上)  进程互斥实验
一、实验环境
Windows 2000,VC++ 6.0。
二、实验目的
1、自己设计程序实现Windows系统中线程的创建;
2、设计实现主线程向子线程传递参数;
3、设计实现线程间的互斥运行。
三、实验原理
1)线程的创建
Win32 提供了一系列的API函数来完成线程的创建、挂起、恢复、终结以及通信等工作。下面将选取其中的一些重要函数进行说明。
① HANDLE CreateThread(LPSECURITY_ATTRIBUTES lpThreadAttributes,
DWORD dwStackSize,
LPTHREAD_START_ROUTINE lpStartAddress,
LPVOID lpParameter,
DWORD dwCreationFlags,
LPDWORD lpThreadId);
该函数在其调用进程的进程空间里创建一个新的线程,并返回已建线程的句柄,其中各参数说明如下:
lpThreadAttributes:指向一个 SECURITY_ATTRIBUTES 结构的指针,该结构决定了线程的安全属性,一般置为 NULL;
dwStackSize:指定了线程的堆栈深度,一般都设置为0;
lpStartAddress:表示新线程开始执行时代码所在函数的地址,即线程的起始地址。一般情况为(LPTHREAD_START_ROUTINE)ThreadFunc,ThreadFunc 是线程函数名;
lpParameter:指定了线程执行时传送给线程的32位参数,即线程函数的参数;
dwCreationFlags:控制线程创建的附加标志,可以取两种值。如果该参数为0,线程在被创建后就会立即开始执行;如果该参数为CREATE_SUSPENDED,则系统产生线程后,该线程处于挂起状态,并不马上执行,直至函数ResumeThread被调用;
lpThreadId:该参数返回所创建线程的ID;
如果创建成功则返回线程的句柄,否则返回NULL。
② DWORD SuspendThread(HANDLE hThread);
该函数用于挂起指定的线程,如果函数执行成功,则线程的执行被终止。
③ DWORD ResumeThread(HANDLE hThread);
该函数用于结束线程的挂起状态,执行线程。
④ VOID ExitThread(DWORD dwExitCode);
该函数用于线程终结自身的执行,主要在线程的执行函数中被调用。其中参数dwExitCode用来设置线程的退出码。
⑤ BOOL TerminateThread(HANDLE hThread,DWORD dwExitCode);
  一般情况下,线程运行结束之后,线程函数正常返回,但是应用程序可以调用TerminateThread强行终止某一线程的执行。各参数含义如下:
hThread:将被终结的线程的句柄;
dwExitCode:用于指定线程的退出码。
  使用TerminateThread()终止某个线程的执行是不安全的,可能会引起系统不稳定;虽然该函数立即终止线程的执行,但并不释放线程所占用的资源。因此,一般不建议使用该函数。
⑥ BOOL PostThreadMessage(DWORD idThread,
UINT Msg,
WPARAM wParam,
LPARAM lParam);
该函数将一条消息放入到指定线程的消息队列中,并且不等到消息被该线程处理时便返回。
idThread:将接收消息的线程的ID;
Msg:指定用来发送的消息;
wParam:同消息有关的字参数;
lParam:同消息有关的长参数;
调用该函数时,如果即将接收消息的线程没有创建消息循环,则该函数执行失败。
2)互斥量的创建
互斥量的作用是保证每次只能有一个线程获得互斥量而得以继续执行,使用CreateMutex函数创建:
HANDLE CreateMutex(
LPSECURITY_ATTRIBUTES lpMutexAttributes,
// 安全属性结构指针,可为NULL
BOOL bInitialOwner, // 当前建立互斥量是否占有该互斥量
//TRUE表示占有,这样其他线程就不能获得此互斥量也就无法进入由
//该互斥量控制的临界区。FALSE表示不占有该互斥量
LPCTSTR lpName // 信号量的名称,字符数不可多于MAX_PATH
//如果遇到同名的其他信号量函数就会失败,如果遇到同类信号同名
//也要注意变化
);
3)阻塞函数
如果等待的信号量不可用,那么线程就会挂起,直到信号可用线程才会被唤醒,该函数会自动修改信号,如Event,线程被唤醒之后Event信号会变得无信号,Mutex、Semaphore等也会变。我们使用WaitForSingleObject函数等待信号,如果要等待多个信号可以使用WaitForMutipleObject函数。
DWORD WaitForSingleObject(
HANDLE hHandle, // 等待对象的句柄
DWORD dwMilliseconds // 等待毫秒数,INFINITE表示无限等待
);
参数hHandle是一个事件的句柄,第二个参数dwMilliseconds是时间间隔。如果时间是有信号状态返回WAIT_OBJECT_0,如果时间超过dwMilliseconds值但时间事件还是无信号状态则返回WAIT_TIMEOUT。
hHandle可以是下列对象的句柄:
Change notification 
Console input 
Event 
Job 
Memory resource notification 
Mutex 
Process 
Semaphore 
Thread 
Waitable timer
WaitForSingleObject函数用来检测hHandle事件的信号状态,当函数的执行时间超过dwMilliseconds就返回,但如果参数dwMilliseconds为INFINITE时函数将直到相应时间事件变成有信号状态才返回,否则就一直等待下去,直到WaitForSingleObject有返回直才执行后面的代码。
四、实验步骤
(1)画出程序流程图
(2)编写程序源代码
线程创建:
#include "stdafx.h"
#include <windows.h>
#include "stdio.h"

int i=2;

DWORD WINAPI clientthread(LPVOID lpparam)
{
int num=(int)lpparam;


i++;
printf("%d,%d",num,i);

return 0;
}

int main(int argc, char* argv[])
{
int num=1;
HANDLE hthread;
DWORD dwthreadid;

hthread=CreateThread(NULL,0,clientthread,(LPVOID)num,0,&dwthreadid);
if(hthread==NULL){
printf("fail55\n");
}
WaitForSingleObject(hthread,2000);
CloseHandle(hthread);

return 0;
}
线程互斥:
#include "stdafx.h"
#include "windows.h"
#include "stdio.h"

HANDLE hMutex,hConsole;


DWORD WINAPI clientthread1(LPVOID lpparam)
{
int i;
char ch=(char)lpparam;
DWORD currentthreadid;


currentthreadid=GetCurrentThreadId();
Sleep(1000);
WaitForSingleObject(hMutex,INFINITE);
for (i=0;i<=9;i++){
SetConsoleTextAttribute(hConsole,FOREGROUND_RED|FOREGROUND_INTENSITY);
printf("%c",ch);
SetConsoleTextAttribute(hConsole,FOREGROUND_RED|FOREGROUND_GREEN|FOREGROUND_BLUE);
Sleep(300);
}
ReleaseMutex(hMutex);

return 0;
}
DWORD WINAPI clientthread2(LPVOID lpparam)
{
int i;
char ch=(char)lpparam;
DWORD currentthreadid;

currentthreadid=GetCurrentThreadId();

WaitForSingleObject(hMutex,INFINITE);
for (i=0;i<=9;i++){
SetConsoleTextAttribute(hConsole,FOREGROUND_GREEN|FOREGROUND_INTENSITY);
printf("%c",ch);
SetConsoleTextAttribute(hConsole,FOREGROUND_RED|FOREGROUND_GREEN|FOREGROUND_BLUE);
Sleep(400);
}
ReleaseMutex(hMutex);

return 0;
}

int main(int argc, char* argv[])
{
char ch1='A',ch2='B';
HANDLE hthread1,hthread2;
DWORD dwthreadid;

hConsole=GetStdHandle(STD_OUTPUT_HANDLE);
if (hConsole == INVALID_HANDLE_VALUE)
return FALSE;

hMutex=CreateMutex(NULL, FALSE, "PrintMutex");
hthread1=CreateThread(NULL,0,clientthread1,(LPVOID)ch1,0,&dwthreadid);
if(hthread1==NULL){
printf("fail55\n");
}
hthread2=CreateThread(NULL,0,clientthread2,(LPVOID)ch2,0,&dwthreadid);
if(hthread2==NULL){
printf("fail55\n");
}
WaitForSingleObject(hthread1,9000);
WaitForSingleObject(hthread2,9000);
CloseHandle(hMutex);
CloseHandle(hthread1);
CloseHandle(hthread2);

CloseHandle(hConsole);
return 0;
}五、实验结果及分析
实验二(下) 进程同步实验
一、实验环境
Windows 2000,VC++ 6.0。
二、实验目的
1.掌握基本的同步与互斥算法,理解读者、写者模型。
2.学习使用Windows 2000/XP中基本的同步对象,掌握相关API的使用方法。
3.了解Windows 2000/XP中多线程的并发执行机制,实现进程的同步。
三、实验原理
1.同步对象
同步对象是指Windows中用于实现同步与互斥的实体,包括信号量(Semaphore)、互斥量(Mutex)、临界区(Critical Section)和事件(Events)等。本实验中使用到信号量、互斥量和临界区三个同步对象。
同步对象的使用步骤:
创建/初始化同步对象。
请求同步对象,进入临界区(互斥量上锁)。
释放同步对象(互斥量解锁)。
这些对象在一个线程中创建,在其他线程中都可以使用,实现同步与互斥。
2.相关API的功能及使用
我们利用Windows SDK提供的API编程实现实验题目要求,而VC中包含有Windows SDK的所有工具和定义。要使用这些API,需要包含堆这些函数进行说明的SDK头文件——最常见的是Windows.h(特殊的API调用还需要包含其他头文件)。
下面给出的是本实验使用到的API的功能和使用方法简单介绍。
(1) CreateThread
功能——创建一个在调用进程的地址空间中执行的线程
格式
HANDLE CreateThread( LPSECURITY_ATTRIBUTES lpThreadAttributes,
DWORD dwStackSize,
LPTHREAD_START_ROUTINE lpStartAddress,
LPVOID lpParamiter,
DWORD dwCreationFlags,
Lpdword lpThread );
参数说明
lpThreadAttributes——指向一个LPSECURITY_ATTRIBUTES(新线程的安全性描述符)。
dwStackSize——定义原始堆栈大小。
lpStartAddress——指向使用LPTHRAED_START_ROUTINE类型定义的函数。
lpParamiter——定义一个给进程传递参数的指针。
dwCreationFlags——定义控制线程创建的附加标志。
lpThread——保存线程标志符(32位)
(2) CreateMutex
功能——创建一个命名或匿名的互斥量对象
格式
HANDLE CreateMutex(LPSECURITY_ATTRIBUTES lpMutexAttributes,
BOOL bInitialOwner,
LPCTSTR lpName);
参数说明
lpMutexAttributes——必须取值NULL。
bInitialOwner——指示当前线程是否马上拥有该互斥量(即马上加锁)。
lpName——互斥量名称。
(3) CreateSemaphore
功能——创建一个命名或匿名的信号量对象
格式
HANDLE CreateSemaphore(LPSECURITY_ATTRIBUTES lpSemaphoreAttributes,
LONG lInitialCount,
LONG lMaximumCount,
LPCTSTR lpName );
参数说明
lpSemaphoreAttributes——必须取值NULL。
lInitialCount——信号量的初始值。该值大于0,但小于lMaximumCount指定的最大值。
lMaximumCount——信号量的最大值。
lpName——信号量名称。
(4) WaitForSingleObject
功能——使程序处于等待状态,直到信号量hHandle出现(即其值大于等于1)或超过规定的等待时间
格式
DWORD WaitForSingleObject(HANDLE hHandle, DWORD dwMilliseconds);
参数说明
hHandle——信号量指针。
dwMilliseconds——等待的最长时间(INFINITE为无限等待)。
(5) ReleaseSemaphore
功能——对指定信号量加上一个指定大小的量。成功执行则返回非0值
格式
BOOL ReleaseSemaphore(HANDLE hSemaphore,
LONG lReleaseCount,
LPLONG lppreviousCount );
参数说明
hSemaphore——信号量指针。
lReleaseCount——信号量的增量。
lppreviousCount——保存信号量当前值。
(6) ReleaseMutex
功能——打开互斥锁,即把互斥量加1。成功调用则返回0
格式
BOOL ReleaseMutex(HANDLE hMutex);
参数说明
hMutex——互斥量指针。
(7) InitializeCriticalSection
功能——初始化临界区对象
格式
VOID InitializeCriticalSection(LPCRITICAL_SECTION lpCriticalSection);
参数说明
lpCriticalSection——指向临界区对象的指针。
(8) EnterCriticalSection
功能——等待指定临界区对象的所有权
格式
VOID enterCriticalSection(LPCRITICAL_SECTION lpCriticalSection);
参数说明
lpCriticalSection——指向临界区对象的指针。
(9) LeaveCriticalSection
功能——释放指定临界区对象的所有权
格式
VOID LeaveCriticalSection(LPCRITICAL_SECTION lpCriticalSection);
参数说明
lpCriticalSection——指向临界区对象的指针。
四、实验步骤
(1)画出程序流程图
(2)编写程序源代码
// semaphore.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"
#include "windows.h"
#include "stdio.h"

HANDLE hConsole;
HANDLE Wsemaphore;
HANDLE Rsemaphore;
long * Wsemaphorecount;
long * Rsemaphorecount;
int data=0;

DWORD WINAPI clientthread1(LPVOID lpparam)
{
for (;;){
Sleep(1000);
ReleaseSemaphore(Wsemaphore,-1,Wsemaphorecount);
WaitForSingleObject(Wsemaphore,INFINITE);
data++;
ReleaseSemaphore(Rsemaphore,1,Rsemaphorecount);
}

return 0;
}
DWORD WINAPI clientthread2(LPVOID lpparam)
{
for (;;){
ReleaseSemaphore(Rsemaphore,-1,Rsemaphorecount);
WaitForSingleObject(Rsemaphore,INFINITE);
SetConsoleTextAttribute(hConsole,FOREGROUND_RED|FOREGROUND_INTENSITY);
printf("DATA = ");
SetConsoleTextAttribute(hConsole,FOREGROUND_GREEN|FOREGROUND_INTENSITY);
printf("%d\n",data);
ReleaseSemaphore(Wsemaphore,1,Wsemaphorecount);
}
SetConsoleTextAttribute(hConsole,FOREGROUND_RED|FOREGROUND_GREEN|FOREGROUND_BLUE);
return 0;
}



int main(int argc, char* argv[])
{
HANDLE hthread1,hthread2;
DWORD dwthreadid;

hConsole=GetStdHandle(STD_OUTPUT_HANDLE);
if (hConsole == INVALID_HANDLE_VALUE)
return FALSE;

Wsemaphore=CreateSemaphore(NULL, 1,1, "WSemaphore");
Rsemaphore=CreateSemaphore(NULL, 0,1, "RSemaphore");
hthread1=CreateThread(NULL,0,clientthread1,NULL,0,&dwthreadid);
if(hthread1==NULL){
printf("fail55\n");
}
hthread2=CreateThread(NULL,0,clientthread2,NULL,0,&dwthreadid);
if(hthread2==NULL){
printf("fail55\n");
}
WaitForSingleObject(hthread1,INFINITE);
WaitForSingleObject(hthread2,INFINITE);
CloseHandle(Wsemaphore);
CloseHandle(Rsemaphore);
CloseHandle(hthread1);
CloseHandle(hthread2);

return 0;
}五、实验结果及分析

4. 共享内存实验

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
实验三  共享内存实验
一、实验环境
Windows 2000,VC++ 6.0。
二、实验目的
1、设计一个共享内存写程序shmwrite,能向共享内存中写入数据;
2、设计一个共享内存读程序shmread,能从共享内存中读出数据。
三、实验原理
进程之间数据的共享可以用共用内存实现,在Win32中,进程之间共享内存使用的事映射文件。虚拟内存系统具有把实际内存映射到页文件或者交换文件的能力。用户可以把内存映射到任何的映射文件中,包括系统内存页。而利用系统内存页可以实现快捷的内存共享。
利用共有内存实现进程之间的数据共享共有两部:
(1) 使用CreateFileMapping函数创建内存映射文件。此函数需要文件句柄,对于大多数的内存共享应用程序,建此文件句柄设置为0xFFFFFFFF即可。这样的句柄指向系统内存页文件。
HANDLE CreateFileMapping(HANDLE hFile, // 映射文件的句柄, 
        //设为0xFFFFFFFF以创建一个进程间共享的对象LPSECURITY_ATTRIBUTES lpFileMappingAttributes,   // 安全属性
DWORD flProtect,                                         // 保护方式DWORD dwMaximumSizeHigh,                                           //对象的大小
DWORD dwMaximumSizeLow,
LPCTSTR lpName                                             // 必须为映射文件命名
);
(2) 映射文件文件创建成功以后,以其返回的句柄作为参数,调用MapViewOfFile函数为内存映射文件对象创建视图,MapViewOfFile函数将返回指向文件的视图指针。可以利用此视图指针对内存映射文件进行操作,内存的读写简化到了就像普通变量的操作。
LPVOID MapViewOfFile(
HANDLE hFileMappingObject, // 为内存映射文件对象创建视图
DWORD dwDesiredAccess, // 存取模式
DWORD dwFileOffsetHigh, // 64位偏移地址的高32位
DWORD dwFileOffsetLow, // 64位偏移地址的低32位
DWORD dwNumberOfBytesToMap //映射文件大小
);
四、实验步骤
(1)画出程序流程图
(2)编写程序源代码
Shmwrite源代码
//写内存程序
//MemWrite.cpp
#include "stdafx.h"
#include "windows.h"
#include "stdio.h"
class student
{
public:
long ID;
char name[20];
};
void main()
{
HANDLE hMemShare;
student stu;
int stu_num = 30;
student *lpstu;
stu.ID = 20051232;
strcpy(stu.name,"LiMing");
hMemShare = CreateFileMapping((HANDLE)0xFFFFFFFF,NULL,PAGE_READWRITE,0,sizeof(student),"TestMemShare");
if(hMemShare == NULL)
{
printf("Failed to Alloocate");
return;
}
lpstu = (student *)MapViewOfFile(hMemShare, FILE_MAP_WRITE,0,0,sizeof(student));
if(lpstu == NULL)
{
printf("Failed to Map");
return;
}
*lpstu = stu;
while(1){}
UnmapViewOfFile(lpstu);
}
Shmread源代码
//读内存程序
// MemRead.cpp
#include "stdafx.h"
#include "windows.h"
#include "stdio.h"
class student
{
public:
long ID;
char name[20];
};
void main()
{
HANDLE hMemShare;
student stu;
student *lpstu;

stu.ID = 0;
strcpy(stu.name ,"tst");
hMemShare = OpenFileMapping(FILE_MAP_READ,FALSE,"TestMemShare");
if(hMemShare == NULL)
{
printf("File Created Failed");
return;
}

lpstu = (student *)MapViewOfFile(hMemShare, FILE_MAP_READ,0,0,sizeof(student));
if(lpstu == NULL)
{
printf("Failed to Map");
return;
}
stu = *lpstu;
printf("Student ID=%ld\n",stu.ID);
printf("Student's Name:%s\n",stu.name);
UnmapViewOfFile(lpstu);
}
(3)源程序编译运行
五、实验结果及分析

5. 操作系统系统接口实验

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
实验四  操作系统系统接口实验
一、实验环境
Windows 2000,VC++ 6.0。
二、实验目的
1、使用Windows系统的命令接口创建一个文本文件,并利用键盘向文件添加内容;
2、使用Windows系统的图形用户接口创建一个文本文件,并利用文本编辑器向文件添加内容;
3、使用Windows系统的系统调用接口创建一个文本文件,并设计程序向文件添加内容。
三、实验原理
1、利用DOS命令“copy”,“echo”可以在控制台(CON)上创建文本文件,并通过标准输入设备(键盘)向文件添加内容。
2、普通计算机用户都可以使用Windows系统提供的“记事本”、“Word”、“写字板”等工具,直接在图形用户界面下很方便的建立并编辑文本文件。
3、Windows系统提供了诸如fopen()、fclose()、fputc()、fgetc()等系统调用函数,打开并创建一个文件,并向文件添加内容,操作完成再关闭文件。
四、实验步骤
1、dos命令创建文本文件
a.copy con file1.txt(Enter)
1234 (CTRL+Z) (Enter)
b. echo 1234>> c:\file2.txt(Enter)
copy con c:\123.txt
(输入内容)
Ctrl+Z,回车退出
2、图形界面下创建文本文件
使用“记事本”、“Word”或“写字板”。
3、系统调用创建文本文件
#include "stdafx.h"
#include "stdio.h"
#include "stdlib.h"

int main(int argc, char* argv[])
{
FILE *fp;
char ch,filename[10];

scanf("%s",filename);
if((fp=fopen(filename,"w"))==NULL){
printf("cannot open file\n");
return 0;
}
ch=getchar();
while(ch!='#'){
fputc(ch,fp);
putchar(ch);
ch=getchar();
}
putchar(10);
fclose(fp);
return 0;
}
五、实验结果及分析