在Windows中,后台服务与用户模式的进程之间,可能需要通过信号量进行一些同步操作,最近在写类似功能的时候发现,创建Event,Mutex,Semphore时,使用命名的创建方式无法实现同步,两个进程的信号量之间都无反应。
服务端的代码如下:
#include<iostream>
#include<windows.h>
#include<winbase.h>
using namespace std;
#define SLEEP_TIME 50000
typedef void* handle;
typedef WINADVAPI BOOL (WINAPI *PInitializeSecurityDescriptor)(PSECURITY_DESCRIPTOR, DWORD);
typedef WINADVAPI BOOL (WINAPI *PSetSecurityDescriptorDacl)(PSECURITY_DESCRIPTOR, BOOL, PACL, BOOL);
#define LOGFILE "D:\\result.txt"
handle temp=NULL;
static int a=65;
char muname[]={"NewMutex2"};
int errNm;
char *str;
FILE* log;
SECURITY_ATTRIBUTES *g_pSaCms;
SERVICE_STATUS ServiceStatus;
SERVICE_STATUS_HANDLE hStatus;
void ServiceMain(int argc, char** argv);
void ControlHandler(DWORD request);
int InitService();
bool Win32Mutex(char muname[8])
{
HINSTANCE hAdvApi = LoadLibrary("Advapi32.DLL");
PInitializeSecurityDescriptor pInitializeSecurityDescriptor = 0;
PSetSecurityDescriptorDacl pSetSecurityDescriptorDacl = 0;
PSECURITY_DESCRIPTOR pSD = 0;
g_pSaCms = new SECURITY_ATTRIBUTES;
if (g_pSaCms == 0)
{
prinerr();
return 1;
}
memset(g_pSaCms,0X0, sizeof(*g_pSaCms));
g_pSaCms->nLength = sizeof(*g_pSaCms);
g_pSaCms->bInheritHandle = 1;
pSD = new SECURITY_DESCRIPTOR;
if (pSD == 0)
{
printerr();
goto LABEL_CSA_ERROR;
}
pInitializeSecurityDescriptor = (PInitializeSecurityDescriptor)GetProcAddress(hAdvApi,"InitializeSecurityDescriptor");
if (pInitializeSecurityDescriptor == 0)
{
printerr();
goto LABEL_CSA_ERROR;
}
pSetSecurityDescriptorDacl = (PSetSecurityDescriptorDacl)GetProcAddress(hAdvApi, "SetSecurityDescriptorDacl");
if (pSetSecurityDescriptorDacl == 0)
{
goto LABEL_CSA_ERROR;
}
if (!(*pInitializeSecurityDescriptor)(pSD, SECURITY_DESCRIPTOR_REVISION)
|| (!(*pSetSecurityDescriptorDacl)(pSD, TRUE, (PACL)0, FALSE)))
{
goto LABEL_CSA_ERROR;
}
(void)FreeLibrary(hAdvApi);
g_pSaCms->lpSecurityDescriptor=pSD;
goto LABEL_CSA_PASS;
LABEL_CSA_ERROR:
(void)FreeLibrary(hAdvApi);
if (pSD != 0)
{
delete pSD;
pSD = 0;
}
if (g_pSaCms != 0)
{
delete g_pSaCms;
g_pSaCms = 0;
}
LABEL_CSA_PASS:
temp=::CreateMutex(g_pSaCms,0,muname); //for icdcomm
errNm=GetLastError();
if (!temp)
{
print_err();
}
else
{
print_err();
}
if ((!temp) || errNm == ERROR_ALREADY_EXISTS)
{
if(temp)
{
(void)CloseHandle(temp);
a++;
muname[8]=a;
Win32Mutex(muname);
}
else
{
printInf()
}
return 0;
}
return 1;
}
int main()
{
SERVICE_TABLE_ENTRY ServiceTable[2];
ServiceTable[0].lpServiceName = "MemoryStatus";
ServiceTable[0].lpServiceProc = (LPSERVICE_MAIN_FUNCTION)ServiceMain;
ServiceTable[1].lpServiceName = NULL;
ServiceTable[1].lpServiceProc = NULL;
StartServiceCtrlDispatcher(ServiceTable);
return 0;
}
void ServiceMain(int argc, char** argv)
{
int error;
ServiceStatus.dwServiceType = SERVICE_WIN32;
ServiceStatus.dwCurrentState = SERVICE_START_PENDING;
ServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN;
ServiceStatus.dwWin32ExitCode = 0;
ServiceStatus.dwServiceSpecificExitCode = 0;
ServiceStatus.dwCheckPoint = 0;
ServiceStatus.dwWaitHint = 0;
hStatus = RegisterServiceCtrlHandler(
"MemoryStatus",
(LPHANDLER_FUNCTION)ControlHandler);
if (hStatus == (SERVICE_STATUS_HANDLE)0)
{
// Registering Control Handler failed
return;
}
// Initialize Service
error = InitService();
if (error)
{
// Initialization failed
ServiceStatus.dwCurrentState = SERVICE_STOPPED;
ServiceStatus.dwWin32ExitCode = -1;
SetServiceStatus(hStatus, &ServiceStatus);
return;
}
// My service
muname[8]=a;
Win32Mutex(muname);
// We report the running status to SCM.
ServiceStatus.dwCurrentState = SERVICE_RUNNING;
SetServiceStatus (hStatus, &ServiceStatus);
// The worker loop of a service
while (ServiceStatus.dwCurrentState == SERVICE_RUNNING)
{
Sleep(SLEEP_TIME);
}
return;
}
// Control handler function
void ControlHandler(DWORD request)
{
switch(request)
{
case SERVICE_CONTROL_STOP:
ServiceStatus.dwWin32ExitCode = 0;
ServiceStatus.dwCurrentState = SERVICE_STOPPED;
SetServiceStatus (hStatus, &ServiceStatus);
return;
case SERVICE_CONTROL_SHUTDOWN:
ServiceStatus.dwWin32ExitCode = 0;
ServiceStatus.dwCurrentState = SERVICE_STOPPED;
SetServiceStatus (hStatus, &ServiceStatus);
return;
default:
break;
}
// Report current status
SetServiceStatus (hStatus, &ServiceStatus);
return;
}
用户程序如下:
int main()
{
muname[8]=a;
Win32Mutex(muname);
Sleep(SLEEP_TIME);
return 0;
}
查找相关资料发现,在Windows系统中,后台服务程序通常是运行在session0,而用户程序是运行在session1,这两个进程之间如果要实现进程间的同步,创建信号量时,应当用全局的名称进行创建,如下:
char muname[]={"Global\\NewMutex2"};
参考:
https://docs.microsoft.com/zh-cn/windows/win32/termserv/kernel-object-namespaces?redirectedfrom=MSDN
关于session0进程隔离:
https://docs.microsoft.com/en-us/previous-versions/windows/hardware/design/dn653293(v=vs.85)?redirectedfrom=MSDN
评论区