精华内容
下载资源
问答
  • mm是否为null来判断是否用户进程,看了一下源码,记录一下这个过程 先看一下kernel的启动过程中创建的第一个内核线程 start_kernel->sched_init 创建idle线程,看下sched_init函数 void __init sched_...

    今天在看oom相关source code的时候看到kernel用current->mm是否为null来判断是否是用户进程,看了一下源码,记录一下这个过程

    先看一下kernel的启动过程中创建的第一个内核线程

    start_kernel->sched_init 创建idle线程,看下sched_init函数
    
    void __init sched_init(void)
    {
    	int i, j;
    	unsigned long alloc_size = 0, ptr;
    
    #ifdef CONFIG_FAIR_GROUP_SCHED
    	alloc_size += 2 * nr_cpu_ids * sizeof(void **);
    #endif
    #ifdef CONFIG_RT_GROUP_SCHED
    	alloc_size += 2 * nr_cpu_ids * sizeof(void **);
    #endif
    #ifdef CONFIG_CPUMASK_OFFSTACK
    	alloc_size += num_possible_cpus() * cpumask_size();
    #endif
    	if (alloc_size) {
    		ptr = (unsigned long)kzalloc(alloc_size, GFP_NOWAIT);
    
    #ifdef CONFIG_FAIR_GROUP_SCHED
    		root_task_group.se = (struct sched_entity **)ptr;
    		ptr += nr_cpu_ids * sizeof(void **);
    
    		root_task_group.cfs_rq = (struct cfs_rq **)ptr;
    		ptr += nr_cpu_ids * sizeof(void **);
    
    #endif /* CONFIG_FAIR_GROUP_SCHED */
    #ifdef CONFIG_RT_GROUP_SCHED
    		root_task_group.rt_se = (struct sched_rt_entity **)ptr;
    		ptr += nr_cpu_ids * sizeof(void **);
    
    		root_task_group.rt_rq = (struct rt_rq **)ptr;
    		ptr += nr_cpu_ids * sizeof(void **);
    
    #endif /* CONFIG_RT_GROUP_SCHED */
    #ifdef CONFIG_CPUMASK_OFFSTACK
    		for_each_possible_cpu(i) {
    			per_cpu(load_balance_mask, i) = (void *)ptr;
    			ptr += cpumask_size();
    		}
    #endif /* CONFIG_CPUMASK_OFFSTACK */
    	}
    
    #ifdef CONFIG_SMP
    	init_defrootdomain();
    #endif
    
    	init_rt_bandwidth(&def_rt_bandwidth,
    			global_rt_period(), global_rt_runtime());
    
    #ifdef CONFIG_RT_GROUP_SCHED
    	init_rt_bandwidth(&root_task_group.rt_bandwidth,
    			global_rt_period(), global_rt_runtime());
    #endif /* CONFIG_RT_GROUP_SCHED */
    
    #ifdef CONFIG_CGROUP_SCHED
    	list_add(&root_task_group.list, &task_groups);
    	INIT_LIST_HEAD(&root_task_group.children);
    	INIT_LIST_HEAD(&root_task_group.siblings);
    	autogroup_init(&init_task);
    
    #endif /* CONFIG_CGROUP_SCHED */
    
    	for_each_possible_cpu(i) {
    		struct rq *rq;
    
    		rq = cpu_rq(i);
    		raw_spin_lock_init(&rq->lock);
    		rq->nr_running = 0;
    		rq->calc_load_active = 0;
    		rq->calc_load_update = jiffies + LOAD_FREQ;
    		init_cfs_rq(&rq->cfs);
    		init_rt_rq(&rq->rt, rq);
    #ifdef CONFIG_FAIR_GROUP_SCHED
    		root_task_group.shares = ROOT_TASK_GROUP_LOAD;
    		INIT_LIST_HEAD(&rq->leaf_cfs_rq_list);
    		/*
    		 * How much cpu bandwidth does root_task_group get?
    		 *
    		 * In case of task-groups formed thr' the cgroup filesystem, it
    		 * gets 100% of the cpu resources in the system. This overall
    		 * system cpu resource is divided among the tasks of
    		 * root_task_group and its child task-groups in a fair manner,
    		 * based on each entity's (task or task-group's) weight
    		 * (se->load.weight).
    		 *
    		 * In other words, if root_task_group has 10 tasks of weight
    		 * 1024) and two child groups A0 and A1 (of weight 1024 each),
    		 * then A0's share of the cpu resource is:
    		 *
    		 *	A0's bandwidth = 1024 / (10*1024 + 1024 + 1024) = 8.33%
    		 *
    		 * We achieve this by letting root_task_group's tasks sit
    		 * directly in rq->cfs (i.e root_task_group->se[] = NULL).
    		 */
    		init_cfs_bandwidth(&root_task_group.cfs_bandwidth);
    		init_tg_cfs_entry(&root_task_group, &rq->cfs, NULL, i, NULL);
    #endif /* CONFIG_FAIR_GROUP_SCHED */
    
    		rq->rt.rt_runtime = def_rt_bandwidth.rt_runtime;
    #ifdef CONFIG_RT_GROUP_SCHED
    		INIT_LIST_HEAD(&rq->leaf_rt_rq_list);
    		init_tg_rt_entry(&root_task_group, &rq->rt, NULL, i, NULL);
    #endif
    
    		for (j = 0; j < CPU_LOAD_IDX_MAX; j++)
    			rq->cpu_load[j] = 0;
    
    		rq->last_load_update_tick = jiffies;
    
    #ifdef CONFIG_SMP
    		rq->sd = NULL;
    		rq->rd = NULL;
    		rq->cpu_power = SCHED_POWER_SCALE;
    		rq->post_schedule = 0;
    		rq->active_balance = 0;
    		rq->next_balance = jiffies;
    		rq->push_cpu = 0;
    		rq->cpu = i;
    		rq->online = 0;
    		rq->idle_stamp = 0;
    		rq->avg_idle = 2*sysctl_sched_migration_cost;
    
    		INIT_LIST_HEAD(&rq->cfs_tasks);
    
    		rq_attach_root(rq, &def_root_domain);
    #ifdef CONFIG_NO_HZ_COMMON
    		rq->nohz_flags = 0;
    #endif
    #ifdef CONFIG_NO_HZ_FULL
    		rq->last_sched_tick = 0;
    #endif
    #endif
    		init_rq_hrtick(rq);
    		atomic_set(&rq->nr_iowait, 0);
    	}
    
    	set_load_weight(&init_task);
    
    #ifdef CONFIG_PREEMPT_NOTIFIERS
    	INIT_HLIST_HEAD(&init_task.preempt_notifiers);
    #endif
    
    #ifdef CONFIG_RT_MUTEXES
    	plist_head_init(&init_task.pi_waiters);
    #endif
    
    	/*
    	 * The boot idle thread does lazy MMU switching as well:
    	 */
    	atomic_inc(&init_mm.mm_count);
    	enter_lazy_tlb(&init_mm, current);
    
    	/*
    	 * Make us the idle thread. Technically, schedule() should not be
    	 * called from this thread, however somewhere below it might be,
    	 * but because we are the idle thread, we just pick up running again
    	 * when this runqueue becomes "idle".
    	 */
    	init_idle(current, smp_processor_id());
    
    	calc_load_update = jiffies + LOAD_FREQ;
    
    	/*
    	 * During early bootup we pretend to be a normal task:
    	 */
    	current->sched_class = &fair_sched_class;
    
    #ifdef CONFIG_SMP
    	zalloc_cpumask_var(&sched_domains_tmpmask, GFP_NOWAIT);
    	/* May be allocated at isolcpus cmdline parse time */
    	if (cpu_isolated_map == NULL)
    		zalloc_cpumask_var(&cpu_isolated_map, GFP_NOWAIT);
    	idle_thread_set_boot_cpu();
    #endif
    	init_sched_fair_class();
    
    	scheduler_running = 1;
    }

    上面的函数核心就是通过INIT_TASK自定义一个task,并且对相关结构体变量赋值

    #define INIT_TASK(tsk)	\
    {									\
    	.state		= 0,						\
    	.stack		= &init_thread_info,				\
    	.usage		= ATOMIC_INIT(2),				\
    	.flags		= PF_KTHREAD,					\
    	.prio		= MAX_PRIO-20,					\
    	.static_prio	= MAX_PRIO-20,					\
    	.normal_prio	= MAX_PRIO-20,					\
    	.policy		= SCHED_NORMAL,					\
    	.cpus_allowed	= CPU_MASK_ALL,					\
    	.nr_cpus_allowed= NR_CPUS,					\
    	.mm		= NULL,						\
    	.active_mm	= &init_mm,					\
    	.se		= {						\
    		.group_node 	= LIST_HEAD_INIT(tsk.se.group_node),	\
    	},								\
    	.rt		= {						\
    		.run_list	= LIST_HEAD_INIT(tsk.rt.run_list),	\
    		.time_slice	= RR_TIMESLICE,				\
    	},								\
    	.tasks		= LIST_HEAD_INIT(tsk.tasks),			\
    	INIT_PUSHABLE_TASKS(tsk)					\
    	INIT_CGROUP_SCHED(tsk)						\
    	.ptraced	= LIST_HEAD_INIT(tsk.ptraced),			\
    	.ptrace_entry	= LIST_HEAD_INIT(tsk.ptrace_entry),		\
    	.real_parent	= &tsk,						\
    	.parent		= &tsk,						\
    	.children	= LIST_HEAD_INIT(tsk.children),			\
    	.sibling	= LIST_HEAD_INIT(tsk.sibling),			\
    	.group_leader	= &tsk,						\
    	RCU_POINTER_INITIALIZER(real_cred, &init_cred),			\
    	RCU_POINTER_INITIALIZER(cred, &init_cred),			\
    	.comm		= INIT_TASK_COMM,				\
    	.thread		= INIT_THREAD,					\
    	.fs		= &init_fs,					\
    	.files		= &init_files,					\
    	.signal		= &init_signals,				\
    	.sighand	= &init_sighand,				\
    	.nsproxy	= &init_nsproxy,				\
    	.pending	= {						\
    		.list = LIST_HEAD_INIT(tsk.pending.list),		\
    		.signal = {{0}}},					\
    	.blocked	= {{0}},					\
    	.alloc_lock	= __SPIN_LOCK_UNLOCKED(tsk.alloc_lock),		\
    	.journal_info	= NULL,						\
    	.cpu_timers	= INIT_CPU_TIMERS(tsk.cpu_timers),		\
    	.pi_lock	= __RAW_SPIN_LOCK_UNLOCKED(tsk.pi_lock),	\
    	.timer_slack_ns = 50000, /* 50 usec default slack */		\
    	.pids = {							\
    		[PIDTYPE_PID]  = INIT_PID_LINK(PIDTYPE_PID),		\
    		[PIDTYPE_PGID] = INIT_PID_LINK(PIDTYPE_PGID),		\
    		[PIDTYPE_SID]  = INIT_PID_LINK(PIDTYPE_SID),		\
    	},								\
    	.thread_group	= LIST_HEAD_INIT(tsk.thread_group),		\
    	INIT_IDS							\
    	INIT_PERF_EVENTS(tsk)						\
    	INIT_TRACE_IRQFLAGS						\
    	INIT_LOCKDEP							\
    	INIT_FTRACE_GRAPH						\
    	INIT_TRACE_RECURSION						\
    	INIT_TASK_RCU_PREEMPT(tsk)					\
    	INIT_CPUSET_SEQ							\
    	INIT_VTIME(tsk)							\
    }

    其中mm为null,stack=&init_thread_info,flags = PF_KTHREAD

    然后继续在reset_init中会创建init和kthreadd

    static noinline void __init_refok rest_init(void)
    {
    	int pid;
    
    	rcu_scheduler_starting();
    	/*
    	 * We need to spawn init first so that it obtains pid 1, however
    	 * the init task will end up wanting to create kthreads, which, if
    	 * we schedule it before we create kthreadd, will OOPS.
    	 */
    	kernel_thread(kernel_init, NULL, CLONE_FS | CLONE_SIGHAND);
    	numa_default_policy();
    	pid = kernel_thread(kthreadd, NULL, CLONE_FS | CLONE_FILES);
    	rcu_read_lock();
    	kthreadd_task = find_task_by_pid_ns(pid, &init_pid_ns);
    	rcu_read_unlock();
    	complete(&kthreadd_done);
    
    	/*
    	 * The boot idle thread must execute schedule()
    	 * at least once to get things moving:
    	 */
    	init_idle_bootup_task(current);
    	schedule_preempt_disabled();
    	/* Call into cpu_idle with preempt disabled */
    	cpu_startup_entry(CPUHP_ONLINE);
    }

    这里先看一下kernel_thread方法

    pid_t kernel_thread(int (*fn)(void *), void *arg, unsigned long flags)
    {
    	return do_fork(flags|CLONE_VM|CLONE_UNTRACED, (unsigned long)fn,
    		(unsigned long)arg, NULL, NULL);
    }

    也是调用do_fork,但是注意指定了CLONE_VM的flag

    看一下do_fork对于mm处理的copy_mm函数

    static int copy_mm(unsigned long clone_flags, struct task_struct *tsk)
    {
    	struct mm_struct *mm, *oldmm;
    	int retval;
    
    	tsk->min_flt = tsk->maj_flt = 0;
    	tsk->nvcsw = tsk->nivcsw = 0;
    #ifdef CONFIG_DETECT_HUNG_TASK
    	tsk->last_switch_count = tsk->nvcsw + tsk->nivcsw;
    #endif
    
    	tsk->mm = NULL;
    	tsk->active_mm = NULL;
    
    	/*
    	 * Are we cloning a kernel thread?
    	 *
    	 * We need to steal a active VM for that..
    	 */
    	oldmm = current->mm;
    	if (!oldmm)
    		return 0;
    
    	if (clone_flags & CLONE_VM) {
    		atomic_inc(&oldmm->mm_users);
    		mm = oldmm;
    		goto good_mm;
    	}
    
    	retval = -ENOMEM;
    	mm = dup_mm(tsk);
    	if (!mm)
    		goto fail_nomem;
    
    good_mm:
    	tsk->mm = mm;
    	tsk->active_mm = mm;
    	return 0;
    
    fail_nomem:
    	return retval;
    }

    可以看到会先判断当前mm是否为null,为null的情况是怎样的呢,也就是我们前面所说的第一个内核进程idle它的mm就为null

    kthreadd是idle创建的第一个kernel线程,它的mm也为null,后续通过kthread创建线程mm都为null,也就是是内核态创建的

    那么用户态呢,我们看一下init进程的创建过程

    static int __ref kernel_init(void *unused)
    {
    	kernel_init_freeable();
    	/* need to finish all async __init code before freeing the memory */
    	async_synchronize_full();
    	free_initmem();
    	mark_rodata_ro();
    	system_state = SYSTEM_RUNNING;
    	numa_default_policy();
    
    	flush_delayed_fput();
    
    	if (ramdisk_execute_command) {
    		if (!run_init_process(ramdisk_execute_command))
    			return 0;
    		pr_err("Failed to execute %s\n", ramdisk_execute_command);
    	}
    
    	/*
    	 * We try each of these until one succeeds.
    	 *
    	 * The Bourne shell can be used instead of init if we are
    	 * trying to recover a really broken machine.
    	 */
    	if (execute_command) {
    		if (!run_init_process(execute_command))
    			return 0;
    		pr_err("Failed to execute %s.  Attempting defaults...\n",
    			execute_command);
    	}
    	if (!run_init_process("/sbin/init") ||
    	    !run_init_process("/etc/init") ||
    	    !run_init_process("/bin/init") ||
    	    !run_init_process("/bin/sh"))
    		return 0;
    
    	panic("No init found.  Try passing init= option to kernel. "
    	      "See Linux Documentation/init.txt for guidance.");
    }

    这里会检查bootargs传参的init位置和几个绝对路径的init位置,执行init程序,也就是调用execve在内核的实现

    static int run_init_process(const char *init_filename)
    {
    	argv_init[0] = init_filename;
    	return do_execve(init_filename,
    		(const char __user *const __user *)argv_init,
    		(const char __user *const __user *)envp_init);
    }
    int do_execve(const char *filename,
    	const char __user *const __user *__argv,
    	const char __user *const __user *__envp)
    {
    	struct user_arg_ptr argv = { .ptr.native = __argv };
    	struct user_arg_ptr envp = { .ptr.native = __envp };
    	return do_execve_common(filename, argv, envp);
    }

    可以在do_execve_common中看到bprm_mm_init对mm做了处理

    static int bprm_mm_init(struct linux_binprm *bprm)
    {
    	int err;
    	struct mm_struct *mm = NULL;
    
    	bprm->mm = mm = mm_alloc();
    	err = -ENOMEM;
    	if (!mm)
    		goto err;
    
    	err = init_new_context(current, mm);
    	if (err)
    		goto err;
    
    	err = __bprm_mm_init(bprm);
    	if (err)
    		goto err;
    
    	return 0;
    
    err:
    	if (mm) {
    		bprm->mm = NULL;
    		mmdrop(mm);
    	}
    
    	return err;
    }

    这里有创建mm结构体,做一些init的动作,后续会通过search_binary_handler调用elf的load_binary对init的segement的load段建立和mm >vma的映射,用户态的进程都是通过init fork出来的,所以mm不为null,而用户态的线程也是通过用户态的进程通过clone创建出来的,他们的mm指向进程的mm,也不为null

    展开全文
  • C++ 判断进程是否存在

    万次阅读 2012-09-11 17:09:49
    在做服务应用程序时经常遇到一个服务器多个用户登录时会造成服务应用多个进程同时运行,然后影响系统的正常运行。要解决这个问题就需要在系统启动前判断该应用的进程是否运行,从...//判断进程是否存在 //2012-09-10

     

          在做服务应用程序时经常遇到一个服务器多个用户登录时会造成服务应用多个进程同时运行,然后影响系统的正常运行。要解决这个问题就需要在系统启动前判断该应用的进程是否运行,从进程上解决一个应用多个进程的问题。代码如下:

     

    #include <windows.h>  
    #include "psapi.h"  
    #include"stdio.h"
    #include <tlhelp32.h>
    //
    //判断进程是否存在
    //2012-09-10
    BOOL FindProcess()
    {
    	int i=0;
    	PROCESSENTRY32 pe32;
    	pe32.dwSize = sizeof(pe32); 
    	HANDLE hProcessSnap = ::CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
    	if(hProcessSnap == INVALID_HANDLE_VALUE)
    	{
    		i+=0;
    	}
    	BOOL bMore = ::Process32First(hProcessSnap, &pe32);
    	while(bMore)
    	{
    		//printf(" 进程名称:%s \n", pe32.szExeFile);
    		if(stricmp("进程名",pe32.szExeFile)==0)
    		{
    			//printf("进程运行中");
    			i+=1;
    		}
    		bMore = ::Process32Next(hProcessSnap, &pe32);
    	}
    	if(i>1){           //大于1,排除自身
    		return true;
    	}else{
    		return false;
    	}
    }


    调用这个函数,如果存在则自动退出,如果不存在则正常运行。

     

    展开全文
  • php判断进程是否存在

    2017-02-14 13:08:00
    //计划任务定时检测master进程是否存在,不存在则启动,以root用户运行 public function checkMaster() { $cmd = 'ps axu|grep "UctDataWorker masterRun"|grep -v "grep"|wc -l'; $ret = shell_exec("$cmd...
        //计划任务定时检测master进程是否存在,不存在则启动,以root用户运行
        public function checkMaster()
        {
            $cmd = 'ps axu|grep "UctDataWorker masterRun"|grep -v "grep"|wc -l';
            $ret = shell_exec("$cmd");
    
            $ret = rtrim($ret, "\r\n");
    
            if($ret === "0") {
                $path = dirname(__FILE__) . '/index.php';
                $php_path = Config::$php_path;
                $start_master_cmd = "nohup ".$php_path." ".$path." UctDataWorker masterRun >> /data/log/uctWorker.log 2>&1 &";
                $ret = shell_exec("$start_master_cmd");
            }
        }

     

    转载于:https://www.cnblogs.com/dongruiha/p/6397170.html

    展开全文
  • 或者某个服务是否开启, 比如AppleMobileDeviceService.exe 来判断是否启动了Apple移动设备服务, 从而提醒用户.代码1.如果查询的多个进程有存在的,即返回TRUE. // test-process.cpp : 定义控制台应用程序的入口

    场景

    1.有时候通过查询进程映像名称来判断某个程序是否在执行, 比如判断 adb.exe 是否正在运行, 从而不需要再次开启 adb进程; 或者某个服务是否开启, 比如AppleMobileDeviceService.exe 来判断是否启动了Apple移动设备服务, 从而提醒用户.

    代码

    1.如果查询的多个进程有存在的,即返回TRUE.

    
    // test-process.cpp : 定义控制台应用程序的入口点。
    //
    
    #include "stdafx.h"
    #include <Windows.h>
    #include <TlHelp32.h>
    #include <Shlwapi.h>
    #include <iostream>
    
    BOOL FailedBlacklist(WCHAR *wcBlacklist)
    {
        if(wcBlacklist == NULL) return FALSE;
        //make Copy
        WCHAR *wcBlacklistCopy = (WCHAR *) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, (wcslen(wcBlacklist) + 2) * sizeof(WCHAR)); 
        memcpy(wcBlacklistCopy, wcBlacklist, wcslen(wcBlacklist) * sizeof(WCHAR));
        INT32 iBlacklistLen = wcslen(wcBlacklistCopy);
        for(INT32 iIterate = 0; iIterate < iBlacklistLen; iIterate++)
        {
            if(wcBlacklistCopy[iIterate] == L';')
                wcBlacklistCopy[iIterate] = 0x0000;
        }
        BOOL bProcessMatch = FALSE;
        //iterate list
        WCHAR *wcProcName = wcBlacklistCopy;
        while ((*wcProcName) && !bProcessMatch)//Go through each one until we hit a null.
        {
            //iterate processes
            HANDLE hProcessSnap = INVALID_HANDLE_VALUE;
            PROCESSENTRY32 pe32;
            hProcessSnap = CreateToolhelp32Snapshot(TH32CS_SNAPALL, 0);
            if(hProcessSnap == INVALID_HANDLE_VALUE)    
            {
                if(wcBlacklistCopy != NULL) HeapFree(GetProcessHeap(), 0, wcBlacklistCopy);
                return FALSE;
            }
            pe32.dwSize = sizeof(PROCESSENTRY32);
    
            if(!Process32First(hProcessSnap, &pe32)) 
            {
                if(wcBlacklistCopy != NULL) HeapFree(GetProcessHeap(), 0, wcBlacklistCopy);
                return FALSE;
            }
            do
            {
                if(PathMatchSpecW(pe32.szExeFile, wcProcName))  //Check to see if the current string matches the spec
                    bProcessMatch = TRUE;   
            }while(Process32Next(hProcessSnap, &pe32));
            CloseHandle(hProcessSnap);
            if(!bProcessMatch) wcProcName += wcslen(wcProcName) + 1;    
        }
        if(wcBlacklistCopy != NULL) HeapFree(GetProcessHeap(), 0, wcBlacklistCopy);
        return bProcessMatch;
    }
    
    int _tmain(int argc, _TCHAR* argv[])
    {
        std::cout << FailedBlacklist(L"notepad.exe;chrome.exe") << std::endl;
        return 0;
    }
    
    
    

    参考

    ciav7p1

    展开全文
  • Linux后台运行命令: nohup sh run.sh &...nohup : 不挂断的运行,注意并没有后台运行的功能,,就是指,用nohup运行命令可以使命令永久的执行下去,和用户终端没有关系,例如我们断开SSH连接都不会影响...
  • 场景 我们在开发Windows程序时, 安装程序后一般会以admin方式启动程序, 这时候程序的权限一般是admin权限。可如果重新打开程序时, ... 或者由于某些原因我想看这个程序是否管理员模式启动的,如何快速查看呢? ...
  • 用户点击播放按钮时,音乐在服务中播放,然后用用户退出程序(服务进程还在,音乐还继续),所以妥用户点再次进入应用时,我们播放器要处于播放状态,这里我作了简单的处理,判断这个音乐服务是否开启来完成的。...
  • 用户点击播放按钮时,音乐在服务中播放,然后用用户退出程序(服务进程还在,音乐还继续),所以妥用户点再次进入应用时,我们播放器要处于播放状态,这里我作了简单的处理,判断这个音乐服务是否开启来完成的。...
  • 用户点击播放按钮时,音乐在服务中播放,然后用用户退出程序(服务进程还在,音乐还继续),所以妥用户点再次进入应用时,我们播放器要处于播放状态,这里我作了简单的处理,判断这个音乐服务是否开启来完成的。...
  • linux如何查看nginx是否启动

    万次阅读 2018-06-11 10:40:09
    Nginx是一个高性能的反向代理服务器,现在一般作为我们网站或其他Web服务的第一层代理,用户...工具/原料LinuxNginx通过进程判断1第一种方法:查看进程列表并过滤Linux每个应用运行都会产生一个进程,那么我们就可以...
  • 用户点击播放按钮时,音乐在服务中播放,然后用用户退出程序(服务进程还在,音乐还继续),所以妥用户点再次进入应用时,我们播放器要处于播放状态,这里我作了简单的处理,判断这个音乐服务是否开启来完成的。...
  • 用户点击播放按钮时,音乐在服务中播放,然后用用户退出程序(服务进程还在,音乐还继续),所以妥用户点再次进入应用时,我们播放器要处于播放状态,这里我作了简单的处理,判断这个音乐服务是否开启来完成的。...
  • 作者:魏祝林 ... 大家好,好久不见,今天在开发中遇到的一个问题给大家分享一下,我...当用户点击播放按钮时,音乐在服务中播放,然后用用户退出程序(服务进程还在,音乐还继续),所以妥用户点再次进入应用时,我们...
  • 用户点击播放按钮时,音乐在服务中播放,然后用用户退出程序(服务进程还在,音乐还继续),所以妥用户点再次进入应用时,我们播放器要处于播放状态,这里我作了简单的处理,判断这个音乐服务是否开启来完成的。...
  • 一般情况我们都是通过客户端连接服务端或者是通过查看服务器服务端相关进程是否存在来判断来TASKCTL服务的状态。但还是觉得不够直观,有没有其他的方法啦,我查找一些资料后,大概是弄清楚了,都知道TASKCTL4.1由三...
  • 大家好,好久不见,今天在开发中遇到的一个问题给...当用户点击播放按钮时,音乐在服务中播放,然后用用户退出程序(服务进程还在,音乐还继续),所以妥用户点再次进入应用时,我们播放器要处于播放状态,这里我作了简

空空如也

空空如也

1 2 3 4 5 ... 18
收藏数 356
精华内容 142
关键字:

判断进程是否用户启动