让程序只运行一个实例的四种方法(转)
- 格式:docx
- 大小:245.47 KB
- 文档页数:7
怎样限制应用程序只运行一次?32位操作系统中,可以用两种方法实现:1.首先在global external functions声明外部函数如下:FUNCTION long FindWindowA( ulong Winhandle, string wintitle ) Library ″user32″然后在application的 Open 事件中加入如下代码:ulong l_handle, lu_classstring ls_namels_name = ″我的系统″ //此处ls_name为系统主窗口的标题Titlel_handle = FindWindowA(lu_class, ls_name)if l_handle > 0 thenMessageBox(″提示信息″, ″应用程序″ + This.AppName +″已经运行,不能多次启动!″) Halt Closeelseopen(w_main) //此处为系统主窗口end if这种方法是PowerBuilder联机帮助中的一个例子,是以系统主窗口的标题Title作为判别依据,若有其它与此Title同名应用程序在运行,再想启动此程序也会报应用程序已经运行。
你可以将Title 设为“计算器”,然后启动Windows附件中计算器程序,再运行你的PB应用程序试试。
2.声明外部函数:function ulong CreateMutexA (ulong lpMutexAttributes, int bInitialOwner, ref string lpName) library ″kernel32.dll″function ulong GetLastError () library ″kernel32.dll″然后在application的 Open 事件中加入如下代码:ulong ll_mutex, ll_errstring ls_mutex_nameif handle (GetApplication (), false) <> 0 thenls_mutex_name = this.AppName + char (0)ll_mutex = CreateMutexA (0, 0, ls_mutex_name)ll_err = GetLastError ()if ll_err = 183 then//程序已经运行MessageBox (″提示信息″, ″程序已经运行了!″)Halt closeelse//程序未运行open(w_main)end ifelse //开发模式open(w_main)end if这种方法必须在应用程序编译成可执行文件.exe后才有效.。
java单例模式的实际应用Java单例模式是一种常用的设计模式,它可以保证在一个JVM中只存在一个实例对象。
在实际应用中,单例模式可以解决一些特定场景下的问题,提高系统的性能和效率。
一、数据库连接池在使用数据库连接时,每次都需要创建连接对象和释放连接对象,这个过程比较耗时。
如果每次都创建新的连接对象,会导致系统性能下降。
这时可以使用单例模式来创建一个数据库连接池,保证系统中只有一个连接池对象,通过连接池管理连接的创建和释放,提高了系统的性能和效率。
二、日志记录器在系统开发中,通常需要记录系统的运行日志,以供日后排查问题或者监控系统运行状态。
使用单例模式创建一个日志记录器对象,可以保证系统中只有一个日志记录器实例,所有的日志记录都通过这个实例进行操作,便于集中管理和统一处理。
三、配置文件管理器在系统开发中,通常需要读取配置文件中的参数或者属性,以便灵活配置系统的行为。
使用单例模式创建一个配置文件管理器对象,可以保证系统中只有一个配置文件管理器实例,所有的配置文件读取操作都通过这个实例进行,便于统一管理和维护。
四、线程池在多线程编程中,线程的创建和销毁都需要耗费一定的系统资源。
如果每次都创建新的线程,会导致系统资源的浪费。
使用单例模式创建一个线程池对象,可以保证系统中只有一个线程池实例,通过线程池管理线程的创建和销毁,提高了系统的性能和效率。
五、缓存管理器在系统开发中,通常需要缓存一些数据,以提高系统的访问速度。
使用单例模式创建一个缓存管理器对象,可以保证系统中只有一个缓存管理器实例,通过缓存管理器来管理缓存的读取、存储和更新,提高了系统的性能和效率。
六、打印机管理器在某些场景下,需要使用打印机进行打印操作。
如果每次都新建一个打印机对象,会导致系统资源的浪费。
使用单例模式创建一个打印机管理器对象,可以保证系统中只有一个打印机管理器实例,通过打印机管理器来管理打印机的使用,提高了系统的性能和效率。
七、窗口管理器在图形界面编程中,通常需要使用窗口进行用户交互。
单例模式在项目中的应用一、引言单例模式是一种常见的设计模式,在项目开发中具有广泛的应用。
它的主要目的是确保一个类只有一个实例,并提供一个全局的访问点来获取该实例。
本文将介绍单例模式在项目中的应用,并探讨其优势和适用场景。
二、单例模式的定义与特点单例模式是一种创建型设计模式,它通过限制类的实例化次数为1,来确保只有一个实例存在。
它具有以下特点:1. 私有构造函数:单例类的构造函数被私有化,以防止外部代码创建该类的实例。
2. 静态变量:单例类中通常包含一个静态变量来保存唯一的实例。
3. 静态方法:通过静态方法获取该实例,确保全局唯一访问点。
三、单例模式在项目中的应用单例模式在项目开发中有许多实际应用,下面将介绍几个常见的应用场景。
1. 配置信息管理在项目中,通常会有一些配置信息需要全局访问,比如数据库连接信息、系统参数等。
使用单例模式可以将这些配置信息保存在一个单例类中,通过静态方法获取,避免在多个地方重复获取配置信息的操作。
2. 日志记录器在项目开发中,日志记录是非常重要的,可以帮助我们追踪和调试程序。
使用单例模式可以实现一个全局的日志记录器,所有的日志信息将统一保存在该实例中,方便查阅和管理。
3. 缓存管理在大型项目中,通常会使用缓存来提高系统性能。
单例模式可以用来实现缓存管理器,将缓存对象保存在单例类的静态变量中,通过静态方法进行访问和操作。
这样可以确保缓存对象的唯一性,避免重复创建和管理多个缓存实例。
4. 线程池在多线程编程中,线程池是一种常见的优化方式。
单例模式可以用来创建和管理线程池实例,确保线程池的唯一性和全局访问。
通过单例模式,可以方便地在项目中使用线程池,提高系统的并发处理能力。
5. 数据库连接池在使用数据库时,连接池是一种常见的技术,用于管理数据库连接的创建和回收。
单例模式可以用来实现数据库连接池,确保连接池的唯一性和全局访问。
通过单例模式,可以方便地在项目中使用数据库连接池,提高数据库操作的效率和性能。
c语言循环中特定操作只执行一次的方法C语言中,有时候我们需要在循环中执行特定操作,但是希望这个操作只执行一次。
这种需求在实际编程中非常常见,比如在某个条件满足时打印一条提示信息,或者在程序开始时初始化某个变量等。
本文将介绍在C语言中实现这种特定操作只执行一次的方法。
在C语言中,我们可以利用一个标志位来实现特定操作只执行一次的效果。
具体的实现步骤如下:1. 首先,我们需要定义一个标志位变量,用来记录特定操作是否已经执行过。
可以使用一个布尔型变量来表示,比如可以定义一个名为`flag`的变量,初始值为`false`。
2. 在循环开始之前,我们需要先判断标志位的值。
如果标志位为`false`,则执行特定操作,并将标志位设置为`true`,表示特定操作已经执行过了。
3. 在循环中,我们每次都先判断标志位的值。
如果标志位为`true`,则表示特定操作已经执行过了,我们可以跳过这个操作,继续执行下一次循环。
如果标志位为`false`,则执行特定操作,并将标志位设置为`true`。
下面是一个简单的示例代码,演示了如何使用标志位实现特定操作只执行一次:```c#include <stdio.h>int main() {int i;bool flag = false; // 标志位for (i = 0; i < 10; i++) {if (!flag) {printf("特定操作\n");flag = true;}// 循环中的其他操作printf("循环中的其他操作\n");}return 0;}```在上面的示例代码中,我们使用了一个`for`循环来模拟实际情况。
在循环开始之前,我们首先判断标志位的值。
由于初始时标志位为`false`,所以特定操作会被执行一次,并将标志位设置为`true`。
在循环中,我们每次都先判断标志位的值,如果为`true`,则跳过特定操作,继续执行下一次循环;如果为`false`,则执行特定操作,并将标志位设置为`true`。
C基础如何让代码只执⾏⼀次1.0 最简单, 最⾼效的⽅式C 代码运⾏起点 main 就是个⼤单例函数. 如果把函数注册在其⾥⾯, 那么⼀定很可以 :)// 某个库需要初始化的函数void log_init(void) {... ...}int main(int argc, char * argv[]) {... ...extern void log_init(void);log_init()... ...return 0;}是不是, 很轻松的完成了初始化⼯作.不妨赠送⼀个好⽤的宏, ⽤于处理这类事情//// EXTERN_RUN - 简单的声明, 并⽴即使⽤的宏// ftest : 需要执⾏的函数名称// ... : 可变参数, 保留//#define EXTERN_RUN(ftest, ...) \do { \extern void ftest(); \ftest (__VA_ARGS__); \} while(0)⽤起来更简单, 可以插在代码的任何⼀处EXTERN_RUN(log_run);2.0 多线程模式, 如何搞起呢继续看下⾯例⼦ once.c#include <stdio.h>#include <pthread.h>static void _once(void) {static long _cnt;printf("_once _cnt = %ld\n", ++_cnt);}//// pthread_once 感受//int main(int argc, char * argv[]) {pthread_once_t once = PTHREAD_ONCE_INIT;puts("pthread_once 感受开始 ... ");pthread_once(&once, _once);pthread_once(&once, _once);puts("pthread_once 感受结束 ... ");return 0;}gcc -g -Wall -o once.out once.c -lpthread最终运⾏结果, 也是如我们所料那样pthread_once 实际开发中多⽤于初始化线程私有变量. 其内部实现加锁的.不妨问个⼩问题, 如果需要你去实现 pthread_once 你会怎么分析呢 ?这个问题好解答也不好解答.核⼼亮点在于 pthread_once 运⾏的函数实体崩溃了. 多线程之间如何避免死锁.不妨参照下⾯ winds 上⾯ pthread_once ⼀位⼤佬的实现:#include "pthread.h"#include "implement.h"/* [i_a] simple wrapper ensures correct calling convention for all */static void PTW32_CDECLptw32_mcs_lock_cleanup(void *args){ptw32_mcs_local_node_t *node = (ptw32_mcs_local_node_t *)args;ptw32_mcs_lock_release(node);}intpthread_once (pthread_once_t * once_control, void (PTW32_CDECL *init_routine) (void)){if (once_control == NULL || init_routine == NULL){return EINVAL;}if ((PTW32_INTERLOCKED_LONG)PTW32_FALSE ==(PTW32_INTERLOCKED_LONG)PTW32_INTERLOCKED_EXCHANGE_ADD_LONG((PTW32_INTERLOCKED_LONGPTR)&once_control->done, (PTW32_INTERLOCKED_LONG)0)) /* MBR fence */{ptw32_mcs_local_node_t node;ptw32_mcs_lock_acquire((ptw32_mcs_lock_t *)&once_control->lock, &node);if (!once_control->done){#if defined(PTW32_CONFIG_MSVC7)#pragma inline_depth(0)#endifpthread_cleanup_push(ptw32_mcs_lock_cleanup, &node);(*init_routine)();pthread_cleanup_pop(0);#if defined(PTW32_CONFIG_MSVC7)#pragma inline_depth()#endifonce_control->done = PTW32_TRUE;}ptw32_mcs_lock_release(&node);}return 0;} /* pthread_once */核⼼是通过 pthread_cleanup_push 和 pthread_cleanup_pop 解决崩溃死锁问题.当然还有⼀种思路, 可以解决上⾯问题. 不妨往下看.3.0 跳过锁问题, 尝试原⼦操作先举个⼩例⼦#include <stdio.h>static void _once(void) {static long _cnt;printf("_once _cnt = %ld\n", ++_cnt);}//// run once 感受//int main(int argc, char * argv[]) {puts("run once 感受开始 ... ");{static int _done;if (__sync_bool_compare_and_swap(&_done, 0, 1)) {_once();}if (__sync_bool_compare_and_swap(&_done, 0, 1)) {_once();}}puts("run once 感受结束 ... ");return 0;}运⾏展⽰:这⾥通过 GCC 提供的原⼦交换 __sync_bool_compare_and_swap 解决的.不妨继续赠送的封装宏, 来完成上⾯操作#define ONCE_RUN(code) { \static int _done; \if (!_done) { \if (__sync_bool_compare_and_swap(&_done, 0, 1)) { \code \} \} \}因为是原⼦操作, 没有锁那么重, ⾃然出了问题也不会引起死锁问题.当然有⼈说 pthread, __sync_xxx 都是和 GCC 绑定的, 那么 CL 能不能使⽤了. 当然也是可以的.通过上⾯基础封装库⽀持, ⽤ C 写系统应⽤相关代码还是很好搞的.把酒满上, 还能再写⼏⾏代码有问题, 是肯定的. 欢迎指正, 更新是共同提⾼的过程.回头看看, 时间好快呀. 那些个⼀块补习, 为了玩的伙伴们, ⼆胎孩⼦都快上学了.哈哈.咱们⼀线秃头兵还在为了穷⽽冲锋陷阵 (°ー°〃)。
C++实现程序单实例运⾏的两种⽅式简介在我们编写程序的时候,经常会注意到的⼀个问题就是如何能够让程序只运⾏⼀个实例,确保不会让同⼀个程序多次运⾏,从⽽产⽣诸多相同进程,给我们的带来不便呢?那么常⽤的有以下四种⽅法,第⼀种⽅法是通过扫描进程列表⽐对进程名来检测,第⼆种⽅法是通过枚举程序窗⼝的⽅式,第三种⽅法是采⽤共享全局变量来实现,第四种⽅法是通过创建互斥体来实现。
那么在这些⽅法中,第⼀种和第⼆种⽅法是有缺陷的,扫描进程列表⽐对进程名容易对相同进程名字的不同程序产⽣误报,枚举窗⼝不适⽤于⽆窗⼝程序且与扫描进程列表的⽅法也有相同的缺陷。
所以本⽂笔者为⼤家介绍第三种⽅法与第四种⽅法的具体实现。
代码实现1. 互斥体实现⽅式////////////////////////////////////////////////////////////////////// FileName : SingleRunByMutex.cpp// Creator : PeterZheng// Date : 2019/2/16 11:21// Comment : 互斥体实现进程单实例运⾏////////////////////////////////////////////////////////////////////#include <iostream>#include <cstdio>#include <cstdlib>#include <Windows.h>using namespace std;// 使⽤互斥体保证单体运⾏BOOL IsAlreadyRun(){HANDLE hMutex = NULL;hMutex = CreateMutex(NULL, FALSE, "MYFLAG");if (hMutex != NULL){if (ERROR_ALREADY_EXISTS == GetLastError()){ReleaseMutex(hMutex);return TRUE;}}return FALSE;}// 主函数int APIENTRY WinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance, _In_ LPSTR lpCmdLine, _In_ int nShowCmd){if (IsAlreadyRun()){MessageBox(NULL, "This Program is already RUN !", "Tips", MB_OK);}else{MessageBox(NULL, "I am RUN !", "Tips", MB_OK);Sleep(30000);}ExitProcess(0);return 0;}2. 共享全局变量实现⽅式////////////////////////////////////////////////////////////////////// FileName : SingleRunByShareSeg.cpp// Creator : PeterZheng// Date : 2019/2/16 11:40// Comment : 通过共享全局变量的⽅式实现进程单实例运⾏////////////////////////////////////////////////////////////////////#include <iostream>#include <cstdio>#include <cstdlib>#include <Windows.h>using namespace std;// 创建共享内存段#pragma data_seg("sharedata")DWORD dwFlagId = 0xEE;#pragma data_seg()#pragma comment(linker, "/SECTION:sharedata,RWS")// 使⽤共享内存段保证单体运⾏BOOL IsAlreadyRun(){if (dwFlagId == 0xEF){return TRUE;}return FALSE;}// 主函数int APIENTRY WinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance, _In_ LPSTR lpCmdLine, _In_ int nShowCmd) {if (IsAlreadyRun()){MessageBox(NULL, "This Program is already RUN !", "Tips", MB_OK);}else{MessageBox(NULL, "I am RUN !", "Tips", MB_OK);dwFlagId = 0xEF;Sleep(30000);}ExitProcess(0);return 0;}。
单例使用场景单例模式是一种常用的设计模式,它能够确保一个类只有一个实例,并提供一个全局访问点。
在某些特定的场景下,使用单例模式能够有效地解决一些问题,提高代码的可维护性和性能。
本文将从不同的角度探讨单例模式的使用场景。
一、资源共享场景在某些情况下,系统中只需要存在一个共享的资源,比如数据库连接池、线程池、缓存等。
如果每次需要使用这些资源时都创建新的实例,会导致资源的浪费,并且可能会出现竞争条件。
这时候使用单例模式可以确保资源的共享和唯一性,避免资源的重复创建和冲突。
二、配置文件场景在很多应用程序中,都会使用配置文件来存储一些固定的配置信息,比如数据库连接信息、系统参数等。
这些配置信息在整个应用程序中是唯一的,如果每次需要使用配置信息时都读取一次配置文件,会导致性能的损耗。
使用单例模式可以将配置信息读取一次并保存在单例对象中,以后每次需要使用配置信息时直接从单例对象中获取,避免了重复读取配置文件的开销。
三、日志记录场景在大部分应用程序中,都需要记录一些日志信息,比如错误日志、调试日志等。
如果每次记录日志时都创建一个新的日志对象,会导致大量的内存开销,并且可能会出现日志信息的丢失。
使用单例模式可以确保日志对象的唯一性,避免了内存的浪费和日志的丢失。
四、线程池场景在并发编程中,经常需要使用线程池来管理线程的创建和销毁。
如果每次需要执行任务时都创建一个新的线程池,会导致线程的频繁创建和销毁,降低了系统的性能。
使用单例模式可以确保线程池的唯一性,避免了线程的重复创建和销毁,提高了系统的性能。
五、计数器场景在某些应用程序中,需要使用计数器来统计某个事件的发生次数,比如网站的访问量统计、订单的数量统计等。
如果每次统计时都创建一个新的计数器对象,会导致计数的不准确和资源的浪费。
使用单例模式可以确保计数器的唯一性,避免了计数的不准确和资源的浪费。
六、任务调度场景在很多应用程序中,需要使用任务调度来定期执行一些任务,比如定时发送邮件、定时备份数据库等。
限制一个程序同时只能运行一个实例的方法限制一个程序同时只能运行一个实例的方法一般有两种,即使用“信号”与FindWindow,通常第一种方法较为安全,而第二种方法必须知道Window的CLASS(在MFC中是很痛苦的,而且一旦CLASS NAME变了以后程序也要跟着改),否则可能就会出错。
然而这两种方法都只能限制程序运行一次,如果要控制程序运行次数,比如3次,则使用以上的两种方法就会很困难。
前段时间写了一个HOOK函数,其中用到了共享变量,在这个程序写完后我突发奇想,不知道这个东西在EXE文件中是否有用?想到了那就试一试吧,一试,果然蛮爽的,居然也行,当时就想到这样一来如果要限制一个程序同时只能运行一个实例不是很简单,试了一下,当然毫无疑问的程序只运行了一个,代码如下:1、在一个CPP中所有函数实体外加入以下几句#pragma data_seg("SHARDAT")HWND ghMainWnd=NULL; //必须初始化,保存主窗口HANDLE#pragma data_seg()#pragma comment(linker,"/section:SHARDA T,RWS")2、在你的主窗口的OnCreate中对ghMainWnd赋值ghMainWnd = GetSafeHwnd();3、程序运行时(如Initinstance)判断ghMainWnd 是否为NULLif( ghMainWnd!=NULL && IsWindow(ghMainWnd) ){SendMessage( ghMainWnd, WM_YOURMESSAGE, ...return ...}怎么样,比第一种方法简单多了吧,有了以上代码,要限制程序运行次数就简单了,如下:1、在一个CPP中所有函数实体外加入以下几句#pragma data_seg("SHARDAT")HWND ghMainWnd[10]={}; //保存已运行的窗口HANDLE,没太多用int gRuned=0;#pragma data_seg()#pragma comment(linker,"/section:SHARDA T,RWS")2、在你的主窗口的OnCreate中对ghMainWnd赋值if( gRuned<10 )ghMainWnd[gRuned] = GetSafeHwnd();gRuned++;3、注意,必须在适当的时候减小gRuned, 如在OnDestroy中等4、程序运行时(如Initinstance)判断ghMainWnd 是否为NULLif( gRuned>=MAX_RUN ){SendMessage( ghMainWnd, WM_YOURMESSAGE, ...return ...}注意:在对gRuned操作时要注意同步其中MAX_RUN可以保存到REG或INI中,根据不同情况来设定。
准备工作
这个操作必须要求你的文件系统是 NTFS 的。
FAT32文件系统不行哦。
右键点那个盘-> 属性-> 常规选项卡上-> 文件系统会显示你的文件系统。
如果是FAT32的系统,可以将它转成 NTFS 。
(易宝典提醒:转换成 NTFS 有可能会 带来一定麻烦。
比如,如果电脑上装了两个系统, 一个是 Windows 98、Windows ME 这 样早期的系统,老系统认不出 NTFS 的盘符。
)
1. 开始-> 在开始搜索里打cmd ->然后在上面结果列表里右键 cmd ->点以管理 员身份运行。
共皐(HQ.*
B^Lurm®a{v)
(
玄盘舷2 打开(O)
"id
丈屛呈紜:
NTF5
类型
如果你看到一个Windows需要您的许可才能继续的消息,别奇怪,点一下继续确认就行。
2. 打上下面这个命令,然后按回车运行(x代表你的盘符,用你具体的盘符字母替换
掉)。
con vert x: /fs: ntfs
打开(O】
p亘看洋有结果
P BE妻Internet
开始操作
从现有分区中割一块出来做个分区
1. 开始-> 右键计算机-> 管理
2.
在左侧找到存储下面的磁盘管理,点一下选中磁盘管理 3. 右键你要分割的那个分区,选压缩卷。
Windo/vs Live Messenger 下歎 最近隧用的项目 卜
建Widows 会匹
**!' Windows Update 网路 Windows Media Player
Windows 菲片滓
打开(6 彌苣理器(X) 搀零(£)•••
Windovvs DVD Maker
刚G}
所有程席 幵担壌真
默认 映射兩第匪輩圈"…
斷开网捐驱號(6・・
在卓面上显示⑸
重令名(朗)
4.在输入压缩空间量右边调节一个大小,默认情况下是允许的最大值,然后按压缩。
剩下多少空间没有用,可以压缩出来的空间不会超过现有分区大小的一半。
)
你看到一部分空间释放出来了,然后你可以在这部分空间上新建个分区(不管你
5.
L=_O ■ |“| 蜩| 文43^
・(CO M NTFS 如阴(MM 碗 SJTOtft,换 •a.・简单基專 NTFS
决咅!S 好住分区) -HD”.蔺 H 基畜 NTFS
f Ilf
*
—Ifi 盘 0 12402 G8 昧机
CD ROM 0
DVD (D :i JK 性『)
WRJlH)
6.
LJ (U 〕简瑩 SX NTFS 4_■ D. “ 置呈 i_*D»+ i^= 基K NTFS 基工 NTTS ni 状态良好憶统「忘动.页面文件,:驗. 扶誉良好住分区) 状态貝好I 主分区〕 曲Q & 124.02 GB 联叽 (C) 69.48 GB 状态良好( DATA 10^3 G 愈期 当 CD-ROM 0 DVD (D :) DATA2 ( 34.18 GB 状杏良好] 1013 G 未尹配 ■未细■主分区
已从现有分区中分割出了一块. 现在可以在空白位置创建新分区了 右键空白的空间-> 新建简单卷。
(C) 69>43GBI 状誉慣好c 无專璀 □ATA2 ( 34,1 H GB
DATA m 右G
把未分配的空间加到现有分区里
另外教你一个小贴示,如果在磁盘管理器里看到紧跟着一个盘符后面有一块未分配空间,这部分空间可以并到那个盘符:
1. 右键要扩展的分区(那个分区后面必须紧跟着有未分配的空间),然后按扩展卷。
扩星卷向爭
迭輝晞盘
您可以用至少一个蹴盘上的空间来扩展卷o 豔罪鬻I舊脣器驛蠶可用空间’因対不能将碇盘转换为动态磁盘,或可用叨:
卷大小总数⑷〕:最大可用
空间重减选择空间里曲即
CE):
本文链接匕上一莹取消
已选的⑸:。