当前位置:编程学习 > > 正文

php常驻进程(PHP 多进程与信号中断实现多任务常驻内存管理实例方法)

时间:2021-10-15 00:12:33类别:编程学习

php常驻进程

PHP 多进程与信号中断实现多任务常驻内存管理实例方法

本文章基于 pcntl 扩展做的多进程测试。

进程调度策略

父子进程的调度由操作系统来负责,具体先调度子进程还是父进程由系统的调度算法决定,当然可以在父进程加上延时或是调用进程回收函数 pcntl_wait 可以先让子进程先运行,进程回收的目的是释放进程创建时占用的内存空间,防止变成僵尸进程。

信号:

信号称为软中断系统或是叫软中断,功能是向进程发送异步事件通知。

信号编号: 【源码基于 SIGINT,SIGTERM,SIGUSR1 信号,含义请自行查看 kill 命令手册,不在描述】

linux 支持 64 个,有一半为实时信号,一半为非时实信号,这些信号都有自己的编号和对应的整数值。每个信号的编号含义读者可以参阅 linux 相关手册【man 手册看看就知道了】

信号处理函数:

信号一般会绑定相应的功能,有的是默认动作如 SIGKILL,SIGTERM,SIGINT 操作默认操作就是干掉进程,当然我们可以重写覆盖掉,就是通过 pcntl_signal 来覆盖掉。

信号的概念:与硬件中断一个道理,请读者自行参考本人前面撸过的文章或是查看芯片硬件中断原理。

信号的发送:

kill 信号编号 进程 或是按键产品的中断信号或是在源码里可以使用 posix_kill 等函数。

进程是相互隔离的,拥有自己的堆栈空间,除了一些公用的正文【代码区】,同时也有自己的可执行代码,进程运行时,将占用 cpu 的资源,其它进程将无权运行,此时其它进程将为阻塞状态【比如前面撸过的 tcp 服务】,当进程运行结束后【运行到代码的最后一句或是遇到 return 或是遇到 exit 退出进程函数或是遇到信号事件时将会退出】让出权限并释放掉内存,其它进程就有机会运行了。

进程拥有的自己进程描述符,其中比较常用的是进程号 PID,进程运行时会在系统 /proc/PID 下生成相应的进程文件,用户可以自行查看。

每个进程都拥有所属的进程组【进程的集合】,多个进程组集合则是一个会话,创建一个会话是通过一个进程进行创建的,并且此进程不可以为组长进程,此进程将成为会话期的会话首进程,也会成为进程组的进程组长,同时将会脱离控制终端,即使之前的进程绑定了控制终端也会脱离【守护进程的创建】。

文件描述权限掩码【权限屏蔽字】:

umask () 你可以在 linux 运行这个命令,然后创建文件,并查看它的权限【如果你跑完啥也没有发现,说明你还是训练不够 ^_^】

  • ?
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160
  • 161
  • 162
  • 163
  • 164
  • 165
  • 166
  • 167
  • 168
  • 169
  • 170
  • 171
  • 172
  • 173
  • 174
  • 175
  • 176
  • 177
  • 178
  • 179
  • 180
  • 181
  • 182
  • 183
  • 184
  • 185
  • 186
  • 187
  • 188
  • 189
  • 190
  • 191
  • 192
  • 193
  • 194
  • 195
  • 196
  • 197
  • 198
  • 199
  • 200
  • 201
  • 202
  • 203
  • 204
  • 205
  • 206
  • 207
  • 208
  • 209
  • 210
  • 211
  • 212
  • 213
  • 214
  • 215
  • 216
  • 217
  • 218
  • 219
  • 220
  • 221
  • 222
  • 223
  • 224
  • 225
  • 226
  • 227
  • 228
  • 229
  • 230
  • 231
  • 232
  • 233
  • 234
  • 235
  • 236
  • 237
  • 238
  • 239
  • 240
  • 241
  • 242
  • 243
  • 244
  • 245
  • 246
  • 247
  • 248
  • 249
  • 250
  • 251
  • 252
  • 253
  • 254
  • 255
  • 256
  • 257
  • 258
  • 259
  • 260
  • 261
  • 262
  • 263
  • 264
  • 265
  • 266
  • 267
  • 268
  • 269
  • 270
  • 271
  • 272
  • 273
  • 274
  • 275
  • 276
  • 277
  • 278
  • 279
  • 280
  • 281
  • 282
  • 283
  • 284
  • 285
  • 286
  • 287
  • 288
  • 289
  • 290
  • 291
  • 292
  • 293
  • 294
  • 295
  • 296
  • 297
  • 298
  • 299
  • 300
  • 301
  • 302
  • 303
  • 304
  • 305
  • 306
  • 307
  • 308
  • 309
  • 310
  • 311
  • 312
  • 313
  • 314
  • 315
  • 316
  • 317
  • 318
  • 319
  • 320
  • 321
  • 322
  • 323
  • 324
  • 325
  • 326
  • 327
  • 328
  • 329
  • 330
  • 331
  • 332
  • 333
  • 334
  • 335
  • 336
  • 337
  • 338
  • 339
  • 340
  • 341
  • 342
  • 343
  • 344
  • 345
  • 346
  • 347
  • 348
  • 349
  • 350
  • 351
  • 352
  • 353
  • 354
  • 355
  • 356
  • 357
  • 358
  • 359
  • 360
  • 361
  • 362
  • 363
  • 364
  • 365
  • 366
  • 367
  • 368
  • 369
  • 370
  • 371
  • 372
  • 373
  • 374
  • 375
  • 376
  • 377
  • 378
  • 379
  • 380
  • 381
  • 382
  • 383
  • 384
  • 385
  • 386
  • 387
  • 388
  • 389
  • <?php
  •  
  • /**
  •  
  •  * Created by PhpStorm.
  •  
  •  * User: 1655664358@qq.com
  •  
  •  * Date: 2018/3/26
  •  
  •  * Time: 14:19
  •  
  •  */
  •  
  • namespace Chen\Worker;
  •  
  • class Server
  •  
  • {
  •  
  •  public $workerPids = [];
  •  
  •  public $workerJob = [];
  •  
  •  public $master_pid_file = "master_pid";
  •  
  •  public $state_file = "state_file.txt";
  •  
  •  function run()
  •  
  •  {
  •  
  •   $this->daemon();
  •  
  •   $this->worker();
  •  
  •   $this->setMasterPid();
  •  
  •   $this->installSignal();
  •  
  •   $this->showState();
  •  
  •   $this->wait();
  •  
  •  }
  •  
  •  function wait()
  •  
  •  {
  •  
  •   while (1){
  •  
  •    pcntl_signal_dispatch();
  •  
  •    $pid = pcntl_wait($status);
  •  
  •    if ($pid>0){
  •  
  •     unset($this->workerPids[$pid]);
  •  
  •    }else{
  •  
  •     if (count($this->workerPids)==0){
  •  
  •      exit();
  •  
  •     }
  •  
  •    }
  •  
  •    usleep(100000);
  •  
  •   }
  •  
  •  }
  •  
  •  function showState()
  •  
  •  {
  •  
  •   $state = "\nMaster 信息\n";
  •  
  •   $state.=str_pad("master pid",25);
  •  
  •   $state.=str_pad("worker num",25);
  •  
  •   $state.=str_pad("job pid list",10)."\n";
  •  
  •   $state.=str_pad($this->getMasterPid(),25);
  •  
  •   $state.=str_pad(count($this->workerPids),25);
  •  
  •   $state.=str_pad(implode(",",array_keys($this->workerPids)),10);
  •  
  •   echo $state.PHP_EOL;
  •  
  •  }
  •  
  •  function getMasterPid()
  •  
  •  {
  •  
  •   if (file_exists($this->master_pid_file)){
  •  
  •    return file_get_contents($this->master_pid_file);
  •  
  •   }else{
  •  
  •    exit("服务未运行\n");
  •  
  •   }
  •  
  •  }
  •  
  •  function setMasterPid()
  •  
  •  {
  •  
  •   $fp = fopen($this->master_pid_file,"w");
  •  
  •   @fwrite($fp,posix_getpid());
  •  
  •   @fclose($fp);
  •  
  •  }
  •  
  •  function daemon()
  •  
  •  {
  •  
  •   $pid = pcntl_fork();
  •  
  •   if ($pid<0){
  •  
  •    exit("fork进程失败\n");
  •  
  •   }else if ($pid >0){
  •  
  •    exit(0);
  •  
  •   }else{
  •  
  •    umask(0);
  •  
  •    $sid = posix_setsid();
  •  
  •    if ($sid<0){
  •  
  •     exit("创建会话失败\n");
  •  
  •    }
  •  
  •    $pid = pcntl_fork();
  •  
  •    if ($pid<0){
  •  
  •     exit("进程创建失败\n");
  •  
  •    }else if ($pid >0){
  •  
  •     exit(0);
  •  
  •    }
  •  
  •    //可以关闭标准输入输出错误文件描述符【守护进程不需要】
  •  
  •   }
  •  
  •  }
  •  
  •  function worker()
  •  
  •  {
  •  
  •   if (count($this->workerJob)==0)exit("没有工作任务\n");
  •  
  •   foreach($this->workerJob as $job){
  •  
  •    $pid = pcntl_fork();
  •  
  •    if ($pid<0){
  •  
  •     exit("工作进程创建失败\n");
  •  
  •    }else if ($pid==0){
  •  
  •     /***************子进程工作范围**********************/
  •  
  •     //给子进程安装信号处理程序
  •  
  •     $this->workerInstallSignal();
  •  
  •     $start_time = time();
  •  
  •     while (1){
  •  
  •      pcntl_signal_dispatch();
  •  
  •      if ((time()-$start_time)>=$job->job_run_time){
  •  
  •       break;
  •  
  •      }
  •  
  •      $job->run(posix_getpid());
  •  
  •     }
  •  
  •     exit(0);//子进程运行完成后退出
  •  
  •     /***************子进程工作范围**********************/
  •  
  •    }else{
  •  
  •     $this->workerPids[$pid] = $job;
  •  
  •    }
  •  
  •   }
  •  
  •  }
  •  
  •  function workerInstallSignal()
  •  
  •  {
  •  
  •   pcntl_signal(SIGUSR1,[__CLASS__,'workerHandleSignal'],false);
  •  
  •  }
  •  
  •  function workerHandleSignal($signal)
  •  
  •  {
  •  
  •   switch ($signal){
  •  
  •    case SIGUSR1:
  •  
  •     $state = "worker pid=".posix_getpid()."接受了父进程发来的自定义信号\n";
  •  
  •     file_put_contents($this->state_file,$state,FILE_APPEND);
  •  
  •     break;
  •  
  •   }
  •  
  •  }
  • 猜您喜欢