- 環境: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;
}
<br>
> **個人問題記錄:**
起初測試CreateProcess函式是否正確傳參時發現該函式不相容char *型別
![](https://img2024.cnblogs.com/blog/3531058/202410/3531058-20241009001909402-1354116522.png)
- 在 Windows API 中,使用 Unicode 字串時,需要使用 L 字首來定義寬字元字串:
![](https://img2024.cnblogs.com/blog/3531058/202410/3531058-20241009001934208-364686058.png)
<br>
2. 假設有四個執行緒,第一個執行緒輸出字串 “This”,第二個執行緒輸出字串 “is”, 第三個執行緒輸出字串“Jinan”, 第四個執行緒輸出字串 “University!”。編制C/C++程式,在主程式main函式中建立四個執行緒並依次啟動,設計訊號量(Semaphore)同步機制,當主程式執行時,螢幕輸出的結果是字串“This is Jinan University!”
```c
#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() {
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);
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;
}