欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

C++程序自動重啟的實現(xiàn)代碼

 更新時間:2024年04月02日 10:29:55   作者:初級代碼游戲  
自動重啟原理很簡單,用一個進(jìn)程監(jiān)控另一個進(jìn)程,掛了就再啟動一個,細(xì)節(jié)也不算多,主要是正確判斷進(jìn)程狀態(tài)和啟動方式,本文就給大家講講C++程序自動重啟的實現(xiàn)方法,文中有詳細(xì)的代碼示例供大家參考,需要的朋友可以參考下

一、自動重啟的原理

我不知道為什么很多程序員覺得自動重啟很low,就像我始終不明白為什么有些人一聽見我說“重新編譯一下”就笑,難道不是重新編譯一下大部分問題就解決了嗎?

自動重啟原理很簡單,用一個進(jìn)程監(jiān)控另一個進(jìn)程,掛了就再啟動一個。細(xì)節(jié)也不算多,主要是正確判斷進(jìn)程狀態(tài)和啟動方式,其實最大的工作量是程序恢復(fù)時應(yīng)該如何回到原來的狀態(tài),這意味著程序要隨時保存狀態(tài)。

只要你能做到用戶無感,你在背后做了什么用戶在意嗎?

二、自動重啟的實現(xiàn)

如果是UNIX,用fork然后監(jiān)控子進(jìn)程,掛了就再fork,一個循環(huán)就解決問題了。

windows上麻煩一些,監(jiān)控進(jìn)程,控制臺程序:

#include "stdafx.h"
#include "shellapi.h"
#include <stdio.h>
#include <string>
 
using namespace std;
 
bool bDebug = false;
 
int APIENTRY wWinMain(_In_ HINSTANCE hInstance,
	_In_opt_ HINSTANCE hPrevInstance,
	_In_ LPWSTR    lpCmdLine,
	_In_ int       nCmdShow)
{
	UNREFERENCED_PARAMETER(hPrevInstance);
 
	// TODO: 在此處放置代碼。
	if (bDebug)MessageBox(NULL, lpCmdLine, TEXT("啟動"), 0);
 
	wchar_t buf[256];
	DWORD pid = 0;
	{
		LPWSTR* szArglist;
		int nArgs;
		int i;
 
        //從命令行獲取要監(jiān)控的進(jìn)程的PID,參數(shù)-pid后的下一個參數(shù)
		szArglist = CommandLineToArgvW(lpCmdLine, &nArgs);//注意,如果沒有參數(shù),會返回程序名,如果有參數(shù),則不包括程序名(或許是個BUG)
		if (NULL == szArglist)
		{
			MessageBox(NULL, lpCmdLine, TEXT("CommandLineToArgvW失敗"), 0);
			return 0;
		}
		else
		{
			wsprintf(buf, TEXT("參數(shù)個數(shù)%d"), nArgs);
			if (bDebug)MessageBox(NULL, buf, TEXT(""), 0);
			for (i = 0; i < nArgs; ++i)
			{
				if (bDebug)MessageBox(NULL, szArglist[i], TEXT("CommandLineToArgvW"), 0);
				if (0 == _tcsicmp(szArglist[i], TEXT("-pid")) && i + 1 < nArgs)
				{
					pid = _wtol(szArglist[i + 1]);
					wsprintf(buf, TEXT("%u"), pid);
					if (bDebug)MessageBox(NULL, buf, szArglist[i + 1], 0);
				}
			}
		}
 
		LocalFree(szArglist);
	}
	wsprintf(buf, TEXT("%u"), pid);
	if (bDebug)MessageBox(NULL, buf, TEXT("pid"), 0);
 
    //打開進(jìn)程以供監(jiān)控
	HANDLE handle = OpenProcess(PROCESS_QUERY_INFORMATION | SYNCHRONIZE, FALSE, pid);
    //等待進(jìn)程結(jié)束
	DWORD state = WaitForSingleObject(handle, INFINITE);
	if (WAIT_OBJECT_0 == state)
	{
		DWORD exitCode;
		if (!GetExitCodeProcess(handle, &exitCode))//獲得退出碼
		{
			MessageBox(NULL, TEXT("GetExitCodeProcess 出錯"), TEXT("未能獲取程序結(jié)束狀態(tài)"), 0);
		}
		wsprintf(buf, TEXT("退出碼 %u"), exitCode);
		//MessageBox(NULL, buf, TEXT("任務(wù)完成"), 0);
		if (0 != exitCode)//正常退出是返回碼(return 返回碼; 或者exit(返回碼),一般約定正常返回0),異常結(jié)束肯定是非0
		{//這一段就是以-r參數(shù)重啟程序,兩個程序必須在同一目錄下
			wchar_t _app_pathname[MAX_PATH];
			GetModuleFileName(NULL, _app_pathname, MAX_PATH);
			wstring app_pathname = _app_pathname;
			size_t pos = app_pathname.find_last_of('\\');
			if (pos != app_pathname.npos)
			{
				app_pathname.erase(pos + 1);
				app_pathname += TEXT("app.exe");
			}
			else
			{
				app_pathname = TEXT("app.exe");
			}
 
			wchar_t szCmdLine[256];
			wsprintf(szCmdLine, TEXT(" -r"));
 
			PROCESS_INFORMATION   info;
			STARTUPINFO startup;
 
			GetStartupInfo(&startup);
 
			BOOL   bSucc = CreateProcess(app_pathname.c_str(), szCmdLine, NULL, NULL,
				FALSE, NORMAL_PRIORITY_CLASS, NULL, NULL, &startup, &info);
 
			if (!bSucc)
			{
				MessageBox(NULL, TEXT("CreateProcess 出錯"), TEXT("恢復(fù)程序失敗"), 0);
			}
		}
	}
	else if (WAIT_FAILED == state)
	{
		MessageBox(NULL, lpCmdLine, TEXT("WaitForSingleObject失敗"), 0);
	}
	else
	{
		MessageBox(NULL, lpCmdLine, TEXT("WaitForSingleObject非預(yù)期的返回值"), 0);
	}
	return 0;
}

這個程序是這樣的,工作的主程序名叫“app.exe”,在適當(dāng)?shù)臅r候啟動了監(jiān)控進(jìn)程(就是這個代碼,名稱任意,但是必須和app.exe放在一起),并把自己的pid傳遞給監(jiān)控進(jìn)程(命令行參數(shù)-pid 主進(jìn)程),監(jiān)控進(jìn)程啟動后從命令行獲取到需要監(jiān)控的pid,監(jiān)視pid狀態(tài),如果是正常結(jié)束,就退出程序,如果是異常結(jié)束,以“-r”參數(shù)啟動主進(jìn)程。

主進(jìn)程啟動過程是這樣的:啟動到某個階段,檢查命令行,帶有“-r”參數(shù)說明是自動恢復(fù),走自動恢復(fù)流程,否則走正常流程,啟動監(jiān)控進(jìn)程并把自己的pid傳遞過去。

為什么要做一個獨(dú)立的監(jiān)控程序,不用主進(jìn)程自身呢?因為程序太大了,有很多靜態(tài)初始化的話,不知道起兩個會不會有什么問題。

為什么要通過命令行參數(shù)傳遞進(jìn)程PID呢?主進(jìn)程起子進(jìn)程不是可以獲得子進(jìn)程的PID嗎?因為好多程序喜歡套殼啊,返回的子進(jìn)程又創(chuàng)建子進(jìn)程干活,自己馬上就退出了。

獲取自身PID的方法:

DWORD pid = GetCurrentProcessId();

要在驗證程序異常退出可以return一個非零值,或者調(diào)用abort()。如果不區(qū)分是否是重啟則不用處理參數(shù),啟動監(jiān)控進(jìn)程的代碼和監(jiān)控進(jìn)程啟動主進(jìn)程的相似。

三、相關(guān)知識點(diǎn)

3.1 CommandLineToArg

win32程序處理命令行真是費(fèi)勁死了。

shellapi.h
Shell32.dll/Shell32.lib
LPWSTR * CommandLineToArgvW(
  [in]  LPCWSTR lpCmdLine,
  [out] int     *pNumArgs
);

注意參數(shù)pNumArgs是在函數(shù)內(nèi)部分配的,要在外部釋放。這是C的習(xí)慣性做法。

3.2 LocalFree

釋放本地內(nèi)存對象。

HLOCAL LocalFree(
  [in] _Frees_ptr_opt_ HLOCAL hMem
);

3.3 OpenProcess

打開進(jìn)程對象,以便后續(xù)等待進(jìn)程結(jié)束。

HANDLE OpenProcess(
  [in] DWORD dwDesiredAccess,
  [in] BOOL  bInheritHandle,
  [in] DWORD dwProcessId
);

3.4 WaitForSingleObject

等待對象,可以是進(jìn)程、線程、控制臺輸入等類型的句柄,等待的事件包括信號、超時等,發(fā)生了某種事件函數(shù)就會返回。

DWORD WaitForSingleObject(
  [in] HANDLE hHandle,
  [in] DWORD  dwMilliseconds
);

3.5 GetExitCodeProcess

獲得進(jìn)程退出碼。

BOOL GetExitCodeProcess(
  [in]  HANDLE  hProcess,
  [out] LPDWORD lpExitCode
);

3.6 GetModuleFileName

一般用來獲取程序的完整路徑名。

DWORD GetModuleFileNameA(
  [in, optional] HMODULE hModule,
  [out]          LPSTR   lpFilename,
  [in]           DWORD   nSize
);

3.7 GetStartupInfo

獲得程序的啟動信息,在這個代碼里用來傳遞給新進(jìn)程。

void GetStartupInfoW(
  [out] LPSTARTUPINFOW lpStartupInfo
);

3.8 CreateProcess

創(chuàng)建進(jìn)程。

BOOL CreateProcessA(
  [in, optional]      LPCSTR                lpApplicationName,
  [in, out, optional] LPSTR                 lpCommandLine,
  [in, optional]      LPSECURITY_ATTRIBUTES lpProcessAttributes,
  [in, optional]      LPSECURITY_ATTRIBUTES lpThreadAttributes,
  [in]                BOOL                  bInheritHandles,
  [in]                DWORD                 dwCreationFlags,
  [in, optional]      LPVOID                lpEnvironment,
  [in, optional]      LPCSTR                lpCurrentDirectory,
  [in]                LPSTARTUPINFOA        lpStartupInfo,
  [out]               LPPROCESS_INFORMATION lpProcessInformation
);

參數(shù)雖多,大部分都可以不用。

拓展

C++重啟進(jìn)程

步驟:

1、查找需要重啟進(jìn)程的進(jìn)程id

2、啟動需要重啟的進(jìn)程

3、殺死第一步進(jìn)程id的進(jìn)程

代碼:

1、查找需要重啟的進(jìn)程的進(jìn)程id

//通過進(jìn)程名查找進(jìn)程Id
bool FindProcess(std::wstring strProcessName, DWORD& nPid)
{

	TCHAR tszProcess[64] = { 0 };
	lstrcpy(tszProcess, strProcessName.c_str());
	//查找進(jìn)程
	STARTUPINFO st;
	PROCESS_INFORMATION pi;
	PROCESSENTRY32 ps;
	HANDLE hSnapshot;
	memset(&st, 0, sizeof(STARTUPINFO));
	st.cb = sizeof(STARTUPINFO);
	memset(&ps, 0, sizeof(PROCESSENTRY32));
	ps.dwSize = sizeof(PROCESSENTRY32);
	memset(&pi, 0, sizeof(PROCESS_INFORMATION));
	// 遍歷進(jìn)程  
	hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
	if (hSnapshot == INVALID_HANDLE_VALUE)
		return false;
	if (!Process32First(hSnapshot, &ps))
		return false;
	do {
		if (lstrcmp(ps.szExeFile, tszProcess) == 0)
		{
			//找到制定的程序
			nPid = ps.th32ProcessID;
			CloseHandle(hSnapshot);
			return true;
		}
	} while (Process32Next(hSnapshot, &ps));
	CloseHandle(hSnapshot);
	return false;
}

2、啟動進(jìn)程

//啟動進(jìn)程
bool StartPrcess(std::wstring strProcessName)
{
	TCHAR tszProcess[64] = { 0 };
	lstrcpy(tszProcess, strProcessName.c_str());
	//啟動程序
	SHELLEXECUTEINFO shellInfo;
	memset(&shellInfo, 0, sizeof(SHELLEXECUTEINFO));
	shellInfo.cbSize = sizeof(SHELLEXECUTEINFO);
	shellInfo.fMask = NULL;
	shellInfo.hwnd = NULL;
	shellInfo.lpVerb = NULL;
	shellInfo.lpFile = tszProcess;						// 執(zhí)行的程序名(絕對路徑)
	shellInfo.lpParameters = NULL;
	shellInfo.lpDirectory = NULL;
	shellInfo.nShow = SW_MINIMIZE;						//SW_SHOWNORMAL 全屏顯示這個程序
	shellInfo.hInstApp = NULL;
	ShellExecuteEx(&shellInfo);

	return true;
}

3、殺死進(jìn)程

//殺死進(jìn)程
bool KillProcess(DWORD dwPid)
{
	printf("Kill進(jìn)程Pid = %d\n", dwPid); 
	//關(guān)閉進(jìn)程
	HANDLE killHandle = OpenProcess(PROCESS_TERMINATE | PROCESS_QUERY_INFORMATION |   // Required by Alpha
		PROCESS_CREATE_THREAD |   // For CreateRemoteThread
		PROCESS_VM_OPERATION |   // For VirtualAllocEx/VirtualFreeEx
		PROCESS_VM_WRITE,             // For WriteProcessMemory);
		FALSE, dwPid);
	if (killHandle == NULL)
		return false;
	TerminateProcess(killHandle, 0);
	return true;
}

以上就是C++程序自動重啟的實現(xiàn)代碼的詳細(xì)內(nèi)容,更多關(guān)于C++程序自動重啟的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • C++中char[]能修改char*卻不行

    C++中char[]能修改char*卻不行

    本文主要介紹了C++中char[]能修改char*卻不行,文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2021-09-09
  • C語言實現(xiàn)兩個矩陣相乘

    C語言實現(xiàn)兩個矩陣相乘

    這篇文章主要為大家詳細(xì)介紹了C語言實現(xiàn)兩個矩陣相乘的程序,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2018-05-05
  • 詳解CLion配置openMP的方法

    詳解CLion配置openMP的方法

    這篇文章主要介紹了CLion配置openMP的方法,本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2021-02-02
  • C++中delete指針后最好將其置空的操作方法

    C++中delete指針后最好將其置空的操作方法

    C++編程中,當(dāng)你使用delete運(yùn)算符釋放指針?biāo)赶虻膬?nèi)存后,通常將該指針置空,如果一個指針在被刪除后沒有置空,而你在代碼的其他部分再次嘗試刪除同一個指針,可能會導(dǎo)致程序崩潰或產(chǎn)生未定義行為,本文介紹C++中delete指針后最好將其置空的操作方法,感興趣的朋友一起看看吧
    2024-06-06
  • C++實現(xiàn)LeetCode(22.生成括號)

    C++實現(xiàn)LeetCode(22.生成括號)

    這篇文章主要介紹了C++實現(xiàn)LeetCode(22.生成括號),本篇文章通過簡要的案例,講解了該項技術(shù)的了解與使用,以下就是詳細(xì)內(nèi)容,需要的朋友可以參考下
    2021-07-07
  • c++字符串分割的方法

    c++字符串分割的方法

    這篇文章主要介紹了c++字符串分割的方法,幫助大家更好的理解和學(xué)習(xí)c++,感興趣的朋友可以了解下
    2020-08-08
  • C++基于socket UDP網(wǎng)絡(luò)編程實現(xiàn)簡單聊天室功能

    C++基于socket UDP網(wǎng)絡(luò)編程實現(xiàn)簡單聊天室功能

    這篇文章主要為大家詳細(xì)介紹了C++基于socket UDP網(wǎng)絡(luò)編程實現(xiàn)簡單聊天室功能,文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2021-07-07
  • Qt數(shù)據(jù)庫應(yīng)用之實現(xiàn)通用數(shù)據(jù)庫分頁

    Qt數(shù)據(jù)庫應(yīng)用之實現(xiàn)通用數(shù)據(jù)庫分頁

    數(shù)據(jù)庫分頁展示,在所有的涉及到數(shù)據(jù)庫記錄的項目中都是需要的。本文將利用Qt實現(xiàn)通用數(shù)據(jù)庫的分頁展示,感興趣的小伙伴可以跟隨小編學(xué)習(xí)一下
    2022-02-02
  • 詳解C++編程中運(yùn)算符的使用

    詳解C++編程中運(yùn)算符的使用

    這篇文章主要介紹了詳解C++編程中運(yùn)算符的使用,是C++入門學(xué)習(xí)中的基礎(chǔ)知識,需要的朋友可以參考下
    2015-09-09
  • 一篇文章帶你了解C++ static的作用,全局變量和局部變量的區(qū)別

    一篇文章帶你了解C++ static的作用,全局變量和局部變量的區(qū)別

    這篇文章介紹了C++ static的作用,全局變量和局部變量的區(qū)別,需要的朋友可以過來參考下,希望能夠給你帶來幫助
    2021-09-09

最新評論