精华内容
下载资源
问答
  • Qt 之运行一个实例进程

    千次阅读 2016-02-04 17:52:34
    只需要用户运行一个实例进程 用户可以同时运行多个实例进程 一个实例进程的软件有很多,例如:360、酷狗… 多个实例进程的软件也很多,例如:Visual Studio、Qt Ctretor、QQ…下面我们来介绍下如何实现一个实例进程...

    简述

    发布程序的时候,我们往往会遇到这种情况:

    1. 只需要用户运行一个实例进程
    2. 用户可以同时运行多个实例进程

    一个实例进程的软件有很多,例如:360、酷狗…
    多个实例进程的软件也很多,例如:Visual Studio、Qt Ctretor、QQ…

    下面我们来介绍下如何实现一个实例进程。

    | 版权声明:一去、二三里,未经博主允许不得转载。

    QSharedMemory

    使用共享内存来实现,key值唯一,一般可以用组织名+应用名来确定。

    首先,创建一个共享内存区,当第二个进程启动时,判断内存区数据是否建立,如果有,可以激活已打开的窗体,也可以退出。

    当程序crash的时候,不能及时清除共享区数据,导致程序以后不能正常启动。

    int main(int argc, char **argv)
    {
        QApplication app(argc, argv);
    
        QCoreApplication::setOrganizationName("Company");
        QCoreApplication::setApplicationName("AppName");
        QString strKey = QCoreApplication::organizationName() + QCoreApplication::applicationName();
    
        QSharedMemory sharedMemory(strKey);
        if (!sharedMemory.create(512, QSharedMemory::ReadWrite))
        {
            QMessageBox::information(NULL, QStringLiteral("提示"), QStringLiteral("程序已运行!"));
            exit(0);
        }
    
        MainWindow window;
        window.show();
    
        return app.exec();
    }

    QLocalServer

    QSingleApplication.h

    #ifndef SINGLE_APPLICATION_H
    #define SINGLE_APPLICATION_H
    
    #include <QApplication>
    
    class QLocalServer;
    
    class QSingleApplication : public QApplication
    {
        Q_OBJECT
    
    public:
        explicit QSingleApplication(int argc, char **argv);
        // 判断进程是否存在
        bool isRunning();
    
    private slots:
        void newLocalConnection();
    
    private:
        QLocalServer *m_pServer;
        bool m_bRunning;
    };
    
    #endif // SINGLE_APPLICATION_H

    QSingleApplication.cpp

    #include <QLocalSocket>
    #include <QLocalServer>
    #include <QFile>
    #include <QTextStream>
    #include "QSingleApplication.h"
    
    QSingleApplication::QSingleApplication(int argc, char **argv)
        : QApplication(argc, argv),
          m_bRunning(false)
    {
        QCoreApplication::setOrganizationName("Company");
        QCoreApplication::setApplicationName("AppName");
        QString strServerName = QCoreApplication::organizationName() + QCoreApplication::applicationName();
    
        QLocalSocket socket;
        socket.connectToServer(strServerName);
    
        if (socket.waitForConnected(500))
        {
            QTextStream stream(&socket);
            QStringList args = QCoreApplication::arguments();
    
            QString strArg = (args.count() > 1) ? args.last() : "";
            stream << strArg;
            stream.flush();
            qDebug() << "Have already connected to server.";
    
            socket.waitForBytesWritten();
    
            m_bRunning = true;
        }
        else
        {
            // 如果不能连接到服务器,则创建一个
            m_pServer = new QLocalServer(this);
            connect(m_pServer, SIGNAL(newConnection()), this, SLOT(newLocalConnection()));
    
            if (m_pServer->listen(strServerName))
            {
                // 防止程序崩溃,残留进程服务,直接移除
                if ((m_pServer->serverError() == QAbstractSocket::AddressInUseError) && QFile::exists(m_pServer->serverName()))
                {
                    QFile::remove(m_pServer->serverName());
                    m_pServer->listen(strServerName);
                }
            }
        }
    }
    
    void QSingleApplication::newLocalConnection()
    {
        QLocalSocket *pSocket = m_pServer->nextPendingConnection();
        if (pSocket != NULL)
        {
            pSocket->waitForReadyRead(1000);
    
            QTextStream in(pSocket);
            QString strValue;
            in >> strValue;
            qDebug() << QString("The value is: %1").arg(strValue);
    
            delete pSocket;
            pSocket = NULL;
        }
    }
    
    bool QSingleApplication::isRunning()
    {
        return m_bRunning;
    }

    使用方式

    int main(int argc, char **argv)
    {
        QSingleApplication app(argc,argv);
        if (app.isRunning())
        {
            QMessageBox::information(NULL, QStringLiteral("提示"), QStringLiteral("程序已运行!"));
            exit(0);
        }
    
        MainWindow window;
        window.show();
    
        return app.exec();
    }

    QtSingleApplication

    QSingleApplication位于qt-solution里面,并不包含在Qt库中,遵循 LGPL 协议。

    文档、源码、示例见:QtSingleApplication

    任务列表

    运行程序时,遍历任务列表,查看是当前所有运行中的进程,如果当前进程位置在映射路径中可以找到,则说明程序已经运行,否则,未运行。

    更多参考

    展开全文
  • 创建一个进程

    千次阅读 2011-05-01 10:52:00
    创建进程

    知识点:

       创建一个进程需要用到CreateProcess函数,其在MSDN的描述如下:

    The CreateProcess function creates a new process and its primary thread. The new process runs the specified executable file in the security context of the calling process.  

      即这个函数创建了一个新进程和它的主线程。这个新进程在安全环境中调用进程时运行指定的可执行文件。

      这个函数的定义如下:

      BOOL CreateProcess(
      LPCTSTR
    lpApplicationName,                 // name of executable module  可执行文件名
      LPTSTR lpCommandLine,                      // command line string   命令行参数
      LPSECURITY_ATTRIBUTES lpProcessAttributes, // SD   进程安全性
      LPSECURITY_ATTRIBUTES lpThreadAttributes,  // SD   进程安全性
      BOOL bInheritHandles,                      // handle inheritance option   句柄继承选项
      DWORD dwCreationFlags,                     // creation flags   创建时的一些标识
      LPVOID lpEnvironment,                      // new environment block   新进程的环境变量
      LPCTSTR lpCurrentDirectory,                // current directory name   进程的目录
      LPSTARTUPINFO lpStartupInfo,               // startup information   开始信息
      LPPROCESS_INFORMATION lpProcessInformation // process information   进程信息
    );

     

    各个参数具体设置如下:

    1、lpApplicationName:  指向一个字符串选定可执行模块。这个字符串可以是可执行文件的全路径,或者是一部分名字。在一部分名字的情况下,函数会用当前的驱动器和当前的目录来完成指向。如果这个参数是NULL,这个模块名字是第一个被命令行参数限定空间的字符串

    2、lpCommandLine:这个参数是NULL时,函数会用第一个参数,即lpApplicationName指定的字符串作为命令行参数

    3、lpProcessAttributes:指向一个SECURITY_ATTRIBUTES结构体,来决定返回的句柄是否被子进程继承。如果这个参数设置为NULL, 

                                         那将不能被继承。

    4、lpThreadAttributes:同上,只是来决定主线程是否被继承,为NULL时将不能被继承

    5、bInheritHandles:指出新的进程是否会继承当前的进程的句柄。如果是TRUE,则可。反之为FALSE。

    6、dwCreationFlags:指向用来控制优先权类和创建进程的标志。值有很多,具体参看MSDN,这里用的是CREATE_NEW_CONSOLE,

                                    说明进程有新的控制台,而不是继承父进程。

    7、lpEnvironment:如果这个参数为NULL,那么就会用当前进程的环境

    8、lpCurrentDirectory:如果这个参数为NULL,那么就会用当前进程的驱动和目录

    9、lpStartupInfo:Pointer to a STARTUPINFO structure that specifies how the main window for the new process

                                should appear

    10、lpProcessInformation:Pointer to a PROCESS_INFORMATION structure that receives identification information 

                                             about the new process. 

     

       STARTUPINFO结构体的具体参数参照MSDN,本例中,用了其中的俩个参数。dwFlags 和 wShowWindow。第一个参数用来指定有效性,第二个则是指定窗口是否显示。

      而PROCESS_INFORMATION结构体:

       typedef struct _PROCESS_INFORMATION {
        HANDLE hProcess;   新建进程内核句柄
        HANDLE hThread;    新建进程主线程句柄
        DWORD dwProcessId;    新建进程ID
        DWORD dwThreadId;    新建进程主线程ID
    } PROCESS_INFORMATION;

     

    关于ID号:当一个进程对象创建以后,系统会为一个内核对象分配一个唯一ID号,在系统中不会再有其他内核对象的ID号与此相同。

     

    关闭句柄可以用CLoseHandle()函数,参数是要关闭的句柄.

    展开全文
  • 单个进程监听多个端口单个进程创建多个 socket 绑定不同的端口,TCP, UDP 都行多个进程监听同一个端口(multiple processes listen on same port)方式1:通过 fork 创建子进程的方式可以实现,其他情况下不行。连接...

    单个进程监听多个端口

    单个进程创建多个 socket 绑定不同的端口,TCP, UDP 都行


    多个进程监听同一个端口(multiple processes listen on same port)

    方式1:通过 fork 创建子进程的方式可以实现,其他情况下不行。

    当连接到来时,子进程、父进程都可以 accept, 这就是著名的“惊群”问题(thundering herd problem)。

    NGINX 的 master/work 处理方法:

    Flow of an NGINX worker process

    可以设置 ffd 的 close-on-exec flag 避免子进程继承 fd.


    方式2:我们都知道socket是网络上两个进程之间的双向通信链路, 即

    socket = 《A进程的IP地址:端口号,B进程的IP地址:端口号》

    那么有个问题就很有意思了,不同的进程可以监听在同一个IP地址:端口号么?

    根据Unix网络编程中的知识可知,服务端监听一个端口会经历:

    1、根据套接字类型(Ipv4,Ipv6等)创建套接字socket

    2、将套接字bind绑定到具体的网络地址和端口号

    3、调用listen开始在这个套接字上进行监听。

    Unix提供了一个接口setsockopt()可以在bind之前设置套接字选项,其中就包括REUSEADDR这个选项,表明可以多个进程复用bind函数中指定的地址和端口号。

    由此可知多个应用(进程),包括同一个应用多次,都是可以绑定到同一个端口进行监听的。对应地C++、NET等高级语言也都提供了对应的接口。


    从一些例子也可以看出,比如有时候你在服务器上执行netstat -ano可能会发现同一个应用程序在同一个端口上有多个监听,这是因为一些服务端应用程序可能会异常退出或者没有完全释放套接字,但是需要在重新启动时还能够再次监听同一个端口,所以需要能够具备重复监听同一个端口的能力,因此也出现上述情形。


    展开全文
  •  一是如何实现一个守护进程,二是如何检测一个进程是否活着,三是保证某一执行文件只有一个实例在运行。 /*  * 1.守护进程  */ 守护进程的最大特点就是脱离了中断,Linux提供了一个系统调用daemon(),要...

    本文主要包括三个部分:
        一是如何实现一个守护进程,二是如何检测一个进程是否活着,三是保证某一执行文件只有一个实例在运行。

    /*
     * 1.守护进程
     */

    守护进程的最大特点就是脱离了中断,Linux提供了一个系统调用daemon(),要想自定义实现的话,主要包括以下六个步骤:

    1.第一步是使用umask函数,把所有的文件屏蔽字置0。文件屏蔽字是可以继承的,当你有相关操作时,如果你要创建一个文件,继承过来的屏蔽字可能阻止你创建相关属性的文件。比如:如果你明确的创建一个文件为组可读,组可写。如果你没有把屏蔽字清零,那么继承过来的屏蔽字可能不允许你添加这两个属性。

    2.第二步,创建一个子进程,并且令父进程退出。这样做有以下几个好处:一,如果守护进程是一个简单的shell命令启动的,那么父进程的终止可以使shell认为这个命令已经执行结束了。二,子进程继承了父进程的组ID,但又有自己的进程ID,所以我们可以保证目前的子进程不是进程组长。这一步也是我们接下来要用到的setid函数之前的必要条件。

    3.使用setsid函数创建一个新的对会话。首先,该进程变为一个新的会话组的会话头。其次,成为了新的进程组的组长。最后该进程不再控制终端。在system V 下,一些人建议在此时重新fork一次,并且令父进程退出。第二个子进程仍然是一个守护进程。这样做可以保证当前进程不是一个会话组的组长,这样就可以防止他获得控制终端的能力。作为选择,为了防止获得终端的控制权,确定打开终端驱动时明确设置O_NOCTTY。

    4.把当前工作目录变为根目录。当前的工作目录是继承父进程的。守护进程是一直存在的,除非你重启计算机。如果你的守护进程是挂载到文件系统上的,那这个文件系统就不能卸载掉。

    5.不需要的文件描述符应当关掉。这样可以防止守护进程持有从父进程继承过来的文件描述符。我们可以获取最大的文件描述符,或者使用getrlimit函数来决定最大的文件描述符的值。并且全部关闭。(非必要)

    6.一些守护进程把0,1,2这三个文件描述符指向/dev/null,这样的话,当库函数试图通过标准输入输出,标准错误时是没有效果的。当一个守护进程脱离了终端时,就没有地方打印信息;也没有地方接收来自用户的交互式输入。甚至当一个守护进程从一个交互式的会话开始,守护进程在后台运行,登陆会话关闭也不会影响到守护进程。如果其他用户用同样的终端登陆,我们不用设想从守护进程打印信息到终端,也别指望用户读取守护进程。

    以上主要参考:http://www.cnblogs.com/iceocean/articles/1650475.html


    /*
     * 2.如何检查一个进程是否活着
     */
        判断一个进程是否活着,我们主要是通过kill这一系统调用来完成,先看一下kill的manual page:

    [html]  view plain  copy
    1. #include <sys/types.h>  
    2. #include <signal.h>  
    3. int kill(pid_t pid, int sig)  
    4.     DESCRIPTION  
    5.     The  kill()  system  call can be used to send any signal to any process  
    6.     group or process.  
    7.     If pid is positive, then signal sig is sent to pid.  
    8.     If pid equals 0, then sig is sent to every process in the process group  
    9.     of the current process  
    10.     If pid equals -1, then sig is sent to every process for which the call-  
    11.     ing process has permission  to  send  signals,  except  for  process  1  
    12.     (init), but see below.  
    13.     If  pid  is less than -1, then sig is sent to every process in the pro-  
    14.     cess group -pid.  
    15.     If sig is 0, then no signal is sent, but error checking is  still  per-  
    16.     formed.  
    17.     if you can send a signal to PID, and returns 1 if you can't (don't have access or invalid PID)。  

        
        所以kill(pid,0)可以用于检测一个为pid的进程是否还活着[在shell下面可以用ps来查找],基本逻辑如下:

    [cpp]  view plain  copy
    1. if(kill(pid,0)!=0)  
    2.     it's dead.  
    3. else  
    4.     it's alive.  


    /*
     *3.保证某一执行文件只有一个实例在运行
     */
        这样的需求主要是解决保证只有同时只有一个这样的进程在运行,像mysql都这样处理:
        1.启动进程后,先检查pid文件是否存在,存在则读取之前写入的pid,然后用上面的kill(pid,0);来检查是否活着,
        2.活着则退出进程,不允许再启动一个进程,否则启动并将当前的pid写入pid文件。写入的时候要锁住文件,避免
        其他进程也往里面写,主要是lockf这个系统调用,方法是:

    [cpp]  view plain  copy
    1.     /** 
    2.      * @Brief  write the pid into the szPidFile 
    3.      * 
    4.      * @Param szPidFile name of pid file 
    5.      */  
    6. void writePidFile(const char *szPidFile)  
    7. {  
    8.     /*open the file*/  
    9.     char            str[32];  
    10.     int lfp = open(szPidFile, O_WRONLY|O_CREAT|O_TRUNC, 0600);  
    11.     if (lfp < 0) exit(1);  
    12.   
    13.     /*F_LOCK(block&lock) F_TLOCK(try&lock) F_ULOCK(unlock) F_TEST(will not lock)*/  
    14.     if (lockf(lfp, F_TLOCK, 0) < 0) {  
    15.         fprintf(stderr, "Can't Open Pid File: %s", szPidFile);  
    16.         exit(0);  
    17.     }  
    18.   
    19.     /*get the pid,and write it to the pid file.*/  
    20.     sprintf(str, "%d\n", getpid()); // \n is a symbol.  
    21.     ssize_t len = strlen(str);  
    22.     ssize_t ret = write(lfp, str, len);  
    23.     if (ret != len ) {  
    24.         fprintf(stderr, "Can't Write Pid File: %s", szPidFile);  
    25.         exit(0);  
    26.     }  
    27.     close(lfp);  
    28. }  
    展开全文
  • Linux 第一个进程

    千次阅读 2018-08-27 21:28:29
    它是内核运行后的第一个进程. 它的作用你可以在网上查一下. 总的来说功能很多.包括 runlevel, 驱动, 启动服务啥地都会做,感觉事情很多. pid=2 :kthreadd:用于内核线程管理。 pid=3 :migration,用于进程在不同的...
  • 用PowerShell查找一个进程的父进程

    千次阅读 2015-06-18 22:27:15
    在Windows中,我们打开进程任务管理器的时候会发现有许许多多的进程,但是你点击一个进程的时候就会发现他还包含有一些子进程,可能已经没有在做任何处理了,或者夜有可能是某些病毒木马恶意进程,一般没有专用的...
  • Linux命令行下杀死一个进程

    万次阅读 多人点赞 2018-08-22 14:03:11
    top命令:可以实时动态地查看系统的整体运行情况,是一个综合了多方信息监测系统性能和运行信息的实用工具。通过top命令所提供的互动式界面,用热键可以管理。 输入top后可以看到如下的界面,实时显示进程情况。 ...
  • 编写一个守护进程

    千次阅读 2013-06-16 14:36:55
    守护进程-----也就是常说的Daemon进程,是linux后台的服务进程,是一个生存期较长的进程,独立于终端并且周期性的执行某种任务或等待处理某些任务。守护进程在系统引 导时载入时启动,在系统关闭时终止。linux下的...
  • 如何多个进程监听同一个端口

    千次阅读 2020-06-03 11:13:52
    一个进程监听端口,经验告诉我们,如果多次启动一个进程会报错:“Address already in use!"。这是由于bind函数导致的,由于该端口号已经被第一个进程监听了。有哪些方法可以实现多个进程监听同一个端口呢? 2. ...
  • 在 Linux 中杀死一个进程

    千次阅读 2018-06-25 10:40:34
    在 Linux 中,假如一个进程的 PID 为 3810,那么结束一个进程可以使用如下命令: $ kill -9 3810 以 Postman 为例,首先我们需要找到它的进程号,然后才能杀死。 查找进程号使用 ps 命令,不过有一个强大的参数 -...
  • 个进程同时访问同一个文件

    万次阅读 2019-04-08 09:06:06
    但是,个进程写同一文件时,则可能产生预期不到的结果。(可以使用pread,pwrite)。 总结:两个独立进程打开同一文件,对应不同的file对象,每个进程调用close只影响本进程的“打开文件计数”(file对象的引用...
  • 在Linux下我们可以用fork函数创建一个子进程,但是我们需要在一个进程下创建多个子进程时,有些需要注意的地方。假设我们用如下代码在一个进程下创建两个子进程: void main() { pid_t pid1, pid2; pid1 = ...
  • 我们查看进程,准备 kill 进程时,会出现一种情况,有一个进程的 进程id 一直在变化 注意:每一行会出现两个进程号,前一个是自己的进程id,后一个是父级的进程id 如上图,16272,16312,两次都不一样,最后...
  • 进程和线程的区别(超详细)

    万次阅读 多人点赞 2019-10-03 21:57:46
    每个进程都有自己独立的一块内存空间,一个进程可以有多个线程,比如在Windows系统中,一个运行的xx.exe就是一个进程。 线程 进程中的一个执行任务(控制单元),负责当前进程中程序的执行。一个进程至少有一个线程...
  • 进程与线程

    万次阅读 多人点赞 2021-03-17 22:50:20
    进程是系统中独立存在的实体,它可以拥有自己独立的资源,每个进程都拥有自己私有的地址空间,在没有经过进程本身允许的情况下,一个用户进程不可以直接访问其他进程的地址空间 动态性 进程与程序的区别在于,程序只是...
  • linux内核如何启动第一个进程

    千次阅读 2016-12-29 18:46:46
    它是内核运行后的第一个进程. 它的作用你可以在网上查一下.总的来说功能很多.包括 runlevel, 驱动, 启动服务啥地都会做,感觉事情很多. pid=2 :kthreadd:用于内核线程管理。 pid=3 :migration,用于进程在不同的...
  • Linux 查看某一个进程占用内存情况

    万次阅读 2017-06-05 14:32:40
    PID:进程的ID USER:进程所有者 PR:进程的优先级别,越小越优先被执行 NInice:值 VIRT:进程占用的虚拟内存 RES:进程占用的物理内存 SHR:进程使用的共享内存 S:进程的状态。S表示休眠,R表示正在运行,...
  • 在ubuntu中,终止一个进程或终止一个正在运行的程序,一般是通过 kill 、killall、pkill、xkill 等进行。 -------------------------------------------------------------------先看两个例子:  例子一:结束某个...
  • 我们通过PROCESS_BASIC_INFORMATION获取到一个进程P1的父进程的ID时,获取到的其实是P1被创建时创建者进程P1CREATER的id,此时,进程P1CREATER可能已经退出了,而且很有可能此id已被其他进程P2复用了,如果我们在...
  • 4.任何一个进程删除该文件时,另外一个进程不会立即出现读写失败 5.两个进程可以分别读取文件的不同部分而不会相互影响 6.一个进程对文件长度和内容的修改另外一个进程可以立即感知 二:文件描述符与打开文件的关系...
  • Delphi中强制结束一个进程

    千次阅读 2008-02-13 09:09:00
    强制结束一个进程的 API 为 TerminateProcessBOOL TerminateProcess(HANDLE hProcess, // 进程句柄UINT uExitCode // 退出代码 );你可以使用语句 invoke TerminateProcess,structProcInfo.hProcess,0 来结束进程,要...
  • #include #include #include #include int main(void) { pid_t pid1; pid_t pid2; pid1=fork(); /*这里定义第个子进程*/ pid2=fork(); /*这里定义第二个子进程*/ if(pid1
  • 进程-进程标识符

    千次阅读 2017-05-17 19:15:02
    系统给每个进程定义了一个唯一标识该进程的非负正数,称作进程标识符。某一进程终止后,其标识符可以重新用作另一进程的标识符。不过,在任何时刻,一个标识符所代表的进程是唯一的。系统把标识符 0 和 1 保留给...
  • 进程调度

    千次阅读 2019-07-03 14:43:54
    当一个进程从运行状态切换到等待状态。 当一个进程终止。 当一个进程从运行状态切换到就绪状态。 当一个进程从等待状态切换到就绪状态。 1,2两种情形下,操作系统必须选择一个新的进程去执行。当调度只出现1,2两...
  • 、启动 string strPathExe = Environment.CurrentDirectory + "\\FaceRecognition" + "\\IDFaceDemo.exe"; Process process = new System.Diagnostics.Process(); process.StartInfo....
  • Linux下命令行如何KILL掉一个进程

    千次阅读 2018-03-13 23:13:14
    想像一下:你打开了一个程序(可能来自于你的桌面菜单或者命令行),然后开始使用这个程序,没想到程序会锁死、停止运行、或者意外死机。你尝试再次运行该程序,但是它反馈说原来的进程没有完全关闭。你该怎么办?你...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 1,350,798
精华内容 540,319
关键字:

当一个进程