乡下人产国偷v产偷v自拍,国产午夜片在线观看,婷婷成人亚洲综合国产麻豆,久久综合给合久久狠狠狠9

  • <output id="e9wm2"></output>
    <s id="e9wm2"><nobr id="e9wm2"><ins id="e9wm2"></ins></nobr></s>

    • 分享

      運行單個實例

       feiyacz 2012-11-13

      摘自:http://blog.chinaunix.net/space.php?uid=20196318;http://blog.csdn.net/magictong/article/details/3603015

      對于很多服務(wù)來說,在同一個服務(wù)器上只能運行一個實例,那么通過什么方法來保證程序同一時刻只有一個實例運行呢?通過編寫shell腳本來管理程序的啟動、停止是個不錯的方法。在啟動時,shell腳本會創(chuàng)建進程標識文件(存儲正在運行實例的pid)以表明已經(jīng)有實例在運行,如果文件已存在,則說明已有實例在運行,不需要做任何事;在退出時,shell腳本會刪除進程標識文件,表明沒有實例運行。


      shell腳本管理方法在應(yīng)用程序之上再包了一層,那么能不能直接在程序開始運行時自己判斷是否有實例在運行呢,答案是肯定的。原理其實差不多,還是要借助公用資源---文件,當然不僅僅是文件而已,還需要文件鎖的支持。大致思路是這樣的:程序在開始運行時對特定文件進行加鎖(不存在則創(chuàng)建),如果加鎖成功,則實例開始運行;如鎖已經(jīng)被占有,則說明已經(jīng)有實例在運行,則程序直接退出;另外在實例運行完畢后對文件的鎖也隨著丟掉了。這樣就能保證每次只有一個程序?qū)嵗谶\行。


      具體步驟如下:

      1. 打開特定文件(如/var/run/mydaemon.pid),如不存在則創(chuàng)建之;

      2. 使用fcntl對文件整個區(qū)域加勸告鎖。

      3. 如果加鎖成功,則繼續(xù)執(zhí)行后續(xù)代碼,并將pid寫入文件;如加鎖不成功,說明已經(jīng)有實例在運行,直接退出。


      實現(xiàn)示例:

      #include <stdio.h>

      #include <stdlib.h>

      #include <unistd.h>

      #include <fcntl.h>

      #include <printf.h>

      #include <string.h>

      #include <errno.h>

      #include <sys/stat.h>

      #define LOCKFILE "/var/run/mydaemon.pid"

      #define LOCKMODE (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)


      /* set advisory lock on file */

      int lockfile(int fd)

      {

              struct flock fl;

       

              fl.l_type = F_WRLCK;  /* write lock */

              fl.l_start = 0;

              fl.l_whence = SEEK_SET;

              fl.l_len = 0;  //lock the whole file

       

              return(fcntl(fd, F_SETLK, &fl));

      }


      int already_running(const char *filename)

      {

              int fd;

              char buf[16];

       

              fd = open(filename, O_RDWR | O_CREAT, LOCKMODE);

              if (fd < 0) {

                      printf(LOG_ERR, "can't open %s: %m\n", filename);

                      exit(1);

              }

       

              /* 先獲取文件鎖 */

              if (lockfile(fd) == -1) {

                      if (errno == EACCES || errno == EAGAIN) {

                              printf(LOG_ERR, "file: %s already locked", filename);

                              close(fd);

                              return 1;

                      }

                      printf(LOG_ERR, "can't lock %s: %m\n", filename);

                      exit(1);

              }

              /* 寫入運行實例的pid */

              ftruncate(fd, 0);

              sprintf(buf, "%ld", (long)getpid());

              write(fd, buf, strlen(buf) + 1);

              return 0;

      }


      int main(int argc, char *argv[])

      {

              if (already_running(LOCKFILE))

                      return 0;

              /* 在這里添加工作代碼 */

              printf("start main...\n");

              sleep(100);

              printf("main done!\n");

              exit(0);

      }


      綜述:讓一個程序只運行一個實例的方法有多種,但是原理都類似,也就是在程序創(chuàng)建前,有窗口的程序在窗口創(chuàng)建前,檢查系統(tǒng)中是否已經(jīng)設(shè)置了某些特定標志了,如果有說明已經(jīng)有一個實例在運行了,則當前程序通知用戶怎樣怎樣,然后程序退出,當然方法有這么多,各自也就有自己的優(yōu)缺點了。<注意下面的程序都是分塊拷貝的>

       

      方法一:
      我用得做多的方法是創(chuàng)建互斥體Mutex,使用Mutex代碼比較簡潔,但是此時不能取得已經(jīng)啟動的實例窗口局柄,因此無法激活已經(jīng)啟動的實例窗口,代碼如下:
      // -------------------------------------------------------------------------
      // 函數(shù)  : CreateSendingWNDList
      // 功能  : 創(chuàng)建互斥量,用于保證只啟動一個進程
      // 返回值 : int 
      //            成功   0
      //     失敗   -1
      //     存在進程實例 1
      // 附注  : 
      // -------------------------------------------------------------------------
      int CreateSendingWNDList(const TCHAR *pstrKSCoreAppName)
      {
       //-------防止多次起動----------  
       HANDLE hMutex = ::CreateMutex(0, true, pstrKSCoreAppName);
       int nRet = 0;
       if (hMutex)
       { 
        if(GetLastError() == ERROR_ALREADY_EXISTS) 
        {
         nRet = 1;
        }
        else
        {
         nRet = 0;
        }
       }
       else
       {
        nRet = -1;
       }

       return nRet;
      }

      // 在創(chuàng)建窗口前調(diào)用下面代碼
      switch(CreateSendingWNDList(g_strKSCoreAppName))
      {
      case 0: 
       // 正常啟動
       // TODO……

       break;  
      case 1:  
       // 已存在進程,退出
       {
        ::MessageBox(NULL, TEXT("已經(jīng)有一個實例在運行了。"), TEXT("注意"), MB_OK);
       }

      case -1:// 無法創(chuàng)建,退出
      default: 
       return FALSE;
      }

       

      方法二:
      一般來說,使程序只運行一個實例的最簡單的方法當然是使用FindWindow()查找主窗口,如果主窗口已經(jīng)存在了,當然說明已經(jīng)有一個實例運行了。代碼如下:
      // 這種方法有缺陷,窗口名字改變之后就再也找不到了,F(xiàn)indWindow()的參數(shù)ClassName和Caption比較難取得。
      HWND hWnd = FindWindow(NULL, TEXT("SingleInstanceFW"));
      if(IsWindow(hWnd))
      {
       ::MessageBox(NULL, TEXT("已經(jīng)有一個實例在運行了。"), TEXT("注意"), MB_OK);
       ::ShowWindow(hWnd, SW_NORMAL);     // 顯示
       ::SetForegroundWindow(hWnd);       // 激活
       return FALSE;
      }

       

      方法三:

      這種方法相比上面兩種方法,避免上面兩種方法的缺點,通過SetProp()為程序主窗口設(shè)置一個特殊的Property,然后在啟動時遍歷所有的窗口,找出包含著個Property的窗口局柄

      。【這個附加的窗口屬性在窗口銷毀時也應(yīng)該銷毀】這個方法的缺點就是代碼比較多一點,如下:

      // 聲明全局的 屬性 名和 屬性值
      TCHAR g_strKSCoreAppName[] = _T("AFX_KSInstall_CPP__12036F8B_8301_46e2_ADC5_A14A44A85877__");
      HANDLE g_hValue = (HANDLE)1022;

      // 定義枚舉窗口回調(diào)函數(shù)
      BOOL CALLBACK EnumWndProc(HWND hwnd, LPARAM lParam)
      {
       //TCHAR str[200] = {0};
       //::GetWindowText(hwnd, str, 200);
       HANDLE h = GetProp(hwnd, g_strKSCoreAppName);
       if(h == g_hValue)
       {
        *(HWND*)lParam = hwnd;
        return FALSE;
       }
       return TRUE;
      }

      // 主窗口創(chuàng)建前判斷
      HWND oldHWnd = NULL;
      ::EnumWindows(EnumWndProc,(LPARAM)&oldHWnd);    //枚舉所有運行的窗口
      if (oldHWnd != NULL)
      {
       ::MessageBox(NULL, TEXT("已經(jīng)有一個實例在運行了。"), TEXT("注意"), MB_OK);

       ::ShowWindow(oldHWnd, SW_NORMAL);     // 顯示
       ::SetForegroundWindow(oldHWnd);       // 激活
       return FALSE;
      }

      // 主窗口創(chuàng)建后設(shè)置,為窗口附加一個屬性
      ::SetProp(m_hWnd, g_strKSCoreAppName, g_hValue);

      // 主窗口退出時移除該附加屬性
      ::RemoveProp(m_hWnd, g_strKSCoreAppName);

       

      方法四:

      上面的方法二和方法三都有一個弊病,不知道大家發(fā)現(xiàn)沒,那就是依賴于窗口的存在,沒有窗口的程序怎么辦了,用方法一是可以的,不過方法一不太適合即時修改狀態(tài),譬如我想提供選項給用戶,可以即時修改是否允許多實例,像KMP就提供了即時修改是否允許多實例,使用全局變量是一個比較好的解決方案,使用全局共享變量的方法則主要是在VC框架程序中通過編譯器來實現(xiàn)的。通過#pragma data_seg預(yù)編譯指令創(chuàng)建一個新節(jié),在此節(jié)中可用volatile關(guān)鍵字定義一個變量,而且必須對其進行初始化。Volatile關(guān)鍵字指定了變量可以為外部進程訪問。最后,為了使該變量能夠在進程互斥過程中發(fā)揮作用,還要將其設(shè)置為共享變量,同時允許具有讀、寫訪問權(quán)限。這可以通過#pragma comment預(yù)編譯指令來通知編譯器。下面給出使用了全局變量的進程互斥代碼清單:

      #pragma data_seg("Shared") 
      int volatile g_lAppInstance = 0; 
      #pragma data_seg() 
      #pragma comment(linker,"/section:Shared,RWS")

      if (0 == g_lAppInstance)
      {
       g_lAppInstance = 1;
      }
      else if (1 == g_lAppInstance)
      {
       ::MessageBox(NULL, TEXT("已經(jīng)有一個實例在運行了。"), TEXT("注意"), MB_OK);
       return FALSE;
      }
      else
      {
       // 直接啟動
      }

      【注意,代碼應(yīng)該放在程序的入口處】

      其實上面的方法可以兩種進行組合來實現(xiàn)一些比較特殊的需求,具體怎樣就自己去想了。

        本站是提供個人知識管理的網(wǎng)絡(luò)存儲空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點。請注意甄別內(nèi)容中的聯(lián)系方式、誘導購買等信息,謹防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點擊一鍵舉報。
        轉(zhuǎn)藏 分享 獻花(0

        0條評論

        發(fā)表

        請遵守用戶 評論公約

        類似文章 更多