创建进程,设计信号量同步机制,实现多线程同步 - C语言版
- 环境:Windows11
- 编译器:Visual Studio 2019
相关头文件:
#include <windows.h>
#include <stdio.h>
相关函数:
- 睡眠等待函数:
Sleep(int millisecond);
睡眠等待一定时间,会造成OS重新调度其它的线程运行
Sleep(10); //当前线程睡眠10毫秒后重新执行
- 创建进程
CreateProcess(
LPSECURITY_ATTRIBUTES // 是否继承进程句柄
LPSECURITY_ATTRIBUTES //是否继承线程句柄
BOOL bInheritHandles //是否继承句柄
DWORD dwCreationFlags //有没有创建标志
LPVOID lpEnvironment // 是否使用父进程环境变量
LPCTSTR lpCurrentDirectory //使用父进程目录作为当前目录,可以自己设置目录
LPSTARTUPINFO lpStartupInfo //STARTUPINFOW结构体详细信息(启动状态相关信息)
LPPROCESS_INFORMATION //PROCESS_INFORMATION结构体进程信息
);
- 启动线程:
CreateThread(ThreadAttribures, stack_size, ThreadFunctionAddress, Parameters, CreationFlags, ThreadID);
HANDLE t1 = CreateThread(NULL,0,Func,NULL,0,&ThreadID);
- 定义信号量:
Semaphore
HANDLE sema;
- 创建信号量:
CreateSemaphore(Attributes,InitialCount, MaxCount, SemaphoreID);
sema = CreateSemaphore(NULL, 0, 1, NULL);
- 申请访问信号量:
WaitForSingleObject(HANDLE, millisecond);
调用该函数后,如果信号量为0,则线程阻塞;否则信号量当前值减1,然后继续执行下一行语句;
WaitForSingleObject(sema,INFINITE);
- 释放信号量:
ReleaseSemaphore(HANDLE, releaseCount, *PreviousCount);
调用该函数后,信号量当前值加上releastCount,然后继续执行下一行语句;
ReleaseSemaphore(sema,1,NULL); //信号量加1
--- 1. 在程序中根据用户输入的可执行程序名称,创建一个进程来运行该可执行程序。 ```c #define _CRT_SECURE_NO_WARNINGS #include
int main() {
// 定义和初始化STARTUPINFO 和 PROCESS_INFROMATION结构体
STARTUPINFO si;
PROCESS_INFORMATION pi;
ZeroMemory(&si, sizeof(si)); // 将 si 结构体的内存置零,确保其中没有任何残留数据
si.cb = sizeof(si); // 表示结构体的大小
ZeroMemory(&pi, sizeof(pi));
char name[100]; // 接收文件名
char path[100]; // 完整路径
wchar_t wpath[200]; // 宽字符路径
printf("Please input program to run: ");
scanf("%99s", name);
// 将基础路径拷贝到 path 中
strcpy(path, "C:\\Windows\\System32\\");
// 拼接文件名到路径
strcat(path, name);
mbstowcs(wpath, path, sizeof(wpath) / sizeof(wchar_t));
// 创建进程
if (!CreateProcess(
wpath, // 文件路径
NULL, // 命令行参数
NULL, // 默认安全属性
NULL, // 默认安全属性
FALSE, // 不继承句柄
0, // 默认创建标志
NULL, // 使用父进程的环境变量
NULL, // 使用父进程的当前目录
&si, // 启动信息
&pi) // 进程信息
) {
printf("创建进程失败\n");
return -1;
}
// 等待进程结束
WaitForSingleObject(pi.hProcess, INFINITE);
// 关闭进程和线程句柄
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
return 0;
}
个人问题记录:
输出threadNum时,发现for循环里每个输出的threadNum都是4
#define _CRT_SECURE_NO_WARNINGS
#include <windows.h>
#include <stdio.h>
HANDLE sema; // 定义信号量
DWORD WINAPI ThreadFunction(LPVOID lpParam) {
// 申请访问信号量
WaitForSingleObject(sema, INFINITE);
int threadNum = *((int*)lpParam);
printf("%d\n", threadNum);
// 释放信号量
ReleaseSemaphore(sema, 1, NULL);
return 0;
}
int main() {
HANDLE threads[4]; // 存储线程句柄的数组
DWORD threadID;
// 创建信号量,初始计数为0,最大计数为1
sema = CreateSemaphore(NULL, 0, 1, NULL);
if (sema == NULL) {
printf("创建信号量失败\n");
return 1;
}
// 创建并启动线程
for (int i = 0; i < 4; i++) {
threads[i] = CreateThread(
NULL, // 默认安全属性
0, // 默认堆栈大小
ThreadFunction, // 线程函数的地址
&i, // 传递线程编号
0, // 默认创建标志
&threadID // 线程标识符
);
if (threads[i] == NULL) {
printf("线程 %d 启动失败\n", i + 1);
return 1;
}
// 释放信号量
ReleaseSemaphore(sema, 1, NULL);
}
// 等待所有线程完成
WaitForMultipleObjects(4, threads, TRUE, INFINITE);
// 关闭线程句柄
for (int i = 0; i < 4; i++) {
CloseHandle(threads[i]);
}
// 关闭信号量句柄
CloseHandle(sema);
return 0;
}

- 因为传递给线程函数的参数是变量 i 的地址,而在循环中 i 是递增的。所有线程都在共享同一个 i 的地址,所以当所有线程运行时,它们都看到的是 i 的最终值——即循环结束后 i 的值是 4
- 应该为每个线程分配内存:
int* pNum = (int*)malloc(sizeof(int));

- 基于实验题目2,在主函数中依次启动四个线程,修改主程序,使得给定用户任意输入的整数n,程序输出n个同样的字符串“This is Jinan University!”
在题目2的基础上套一层for循环即可
#define _CRT_SECURE_NO_WARNINGS
#include <windows.h>
#include <stdio.h>
HANDLE sema; // 定义信号量
const char* words[] = { "This", "is", "Jinan", "University!" };
DWORD WINAPI ThreadFunction(LPVOID lpParam) {
// 申请访问信号量
WaitForSingleObject(sema, INFINITE);
int threadNum = *((int*)lpParam);
printf("%s ", words[threadNum - 1]);
// 释放信号量
ReleaseSemaphore(sema, 1, NULL);
return 0;
}
int main() {
int n;
printf("n = ");
scanf("%d", &n);
for (int k = 0; k < n; k++) {
HANDLE threads[4]; // 存储线程句柄的数组
DWORD threadID;
// 创建信号量,初始计数为0,最大计数为1
sema = CreateSemaphore(NULL, 0, 1, NULL);
if (sema == NULL) {
printf("创建信号量失败\n");
return 1;
}
// 创建并启动线程
for (int i = 0; i < 4; i++) {
int* pNum = (int*)malloc(sizeof(int)); // 为每个线程分配内存
*pNum = i + 1; // 设置线程编号
threads[i] = CreateThread(
NULL, // 默认安全属性
0, // 默认堆栈大小
ThreadFunction, // 线程函数的地址
pNum, // 传递线程编号
0, // 默认创建标志
&threadID // 线程标识符
);
if (threads[i] == NULL) {
printf("线程 %d 启动失败\n", i + 1);
return 1;
}
// 释放信号量
Sleep(100);
ReleaseSemaphore(sema, 1, NULL);
}
// 等待所有线程完成
WaitForMultipleObjects(4, threads, TRUE, INFINITE);
// 关闭线程句柄
for (int i = 0; i < 4; i++) {
CloseHandle(threads[i]);
}
// 关闭信号量句柄
CloseHandle(sema);
printf("\n");
}
return 0;
}
