文章目录
操作系统可以运行多个程序,那他是如何运行的?实际上,CPU的执行是很快的,而待运行的程序很多,那么为了让操作系统运行多个程序,CPU会把它的执行时间划分成很多段,比如每一段是0.1秒,那么就可以这样A程序运行0.1秒,然后B程序运行0.1,然后C程序运行0.2秒,因为这个切换很快,所以我们感觉程序是同时运行的。
创建进程用法举例:
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
int main(){
int pid = 0;// 父子进程不共享局部变量
// pid_t fork(void);
pid_t fpid = fork(); // fpid表示fork函数返回的值
if(fpid < 0){
printf("创建子进程失败\n");
return fpid;
}else if(fpid == 0){
// 创建成功后子进程中fpid == 0
pid = getpid();
printf("子进程,子进程pid = %d\n",getpid());
}else if(fpid > 0){
// 创建成功后父进程的fpid 为子进程的pid
pid = getpid();
printf("父进程,父进程pid = %d\n",getpid());
printf("父进程,子进程pid = %d\n",getpid());
}
// 再创建3个子进程用于观察
for(int i = 3 ; i > 0 && fpid > 0 ; i--){
fpid = fork();
}
printf("pid = %d\n",pid);
while (1);
return 0;
}

调用fork函数后,会创建一个子进程,并且父子两个进程都从fork处执行,fork函数有两个返回值,对于父进程会返回子进程的pid,此时pid会大于0,对于子进程来说,pid会等于0。
局部变量:写时复制,读时共享
exit - 终止正在执行的进程
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>
int main()
{
int pid = 0;
// pid_t fork(void);
pid_t fpid = fork();
if (fpid < 0)
{
printf("创建子进程失败\n");
return fpid;
}
else if (fpid == 0)
{
printf("我是子进程,马上就要exit了\n");
exit(-1);
printf("子进程还活着\n");
}
else if (fpid > 0)
{
printf("父进程还活着\n");
}
while (1);
return 0;
}
这里子进程已经退出,但是父进程没有执行完毕,导致子进程没有回收变成僵尸进程


优点:
若要用多进程实现高并发那么自己linxu系统cpu有多少核,就产生多少个进程多个核可以并发执行只有多个进程在不同的核上运行才可以充分利用多核系统的并发处理能力
比如:cpu为四核,那么主进程就产生4个子进程,让四个子进程分别在不同的核上运行,
4个子进程在工作的时候,把任务放在一个共享内存中(通过内存映射,使多个进程可以访问一个内存),哪个任务做完了,就接着拿任务给每个子进程的负载均衡
职责明确:父进程管理生死,子进程工作
查看cpu核数
cat /proc/cpuinfo
#define _GNU_SOURCE
#include <sched.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdint.h>
typedef void (*spawn_proc_pt)(void *data);
static void worker_process_cycle(void *data);
static void start_worker_processes(int n);
pid_t spawn_process(spawn_proc_pt proc, void *data, char *name);
int main(int argc, char **argv)
{
// 子进程用于工作,父进程用于管理子进程
// 开启工作进程,创建4个子进程
start_worker_processes(4);
// 管理子进程
wait(NULL);
}
// 开启工作进程
void start_worker_processes(int n)
{
int i = 0;
for (i = n - 1; i >= 0; i--)
{
// 创建子进程
spawn_process(worker_process_cycle, (void *)(intptr_t)i, "worker process");
}
}
// 创建子进程
// spawn_proc_pt 类型的函数:void worker_process_cycle(void *data)
pid_t spawn_process(spawn_proc_pt proc, void *data, char *name)
{
pid_t pid;
pid = fork(); // 创建子进程
switch (pid)
{
case -1:
fprintf(stderr, "fork() failed while spawning \"%s\"\n", name);
return -1;
case 0:
proc(data); // 成功创建子进程后让子进程去工作
return 0;
default:
break;
}
printf("start %s %ld\n", name, (long int)pid);
return pid;
}
// 给进程安排工作
void worker_process_cycle(void *data)
{
// data 其实是一个int*类型
int worker = (intptr_t)data;
// 初始化
worker_process_init(worker);
// 干活
for (;;)
{
sleep(10);
printf("pid %ld ,doing ...\n", (long int)getpid());
}
}
// 初始化进程
void worker_process_init(int worker)
{
cpu_set_t cpu_affinity;
// worker = 2;
// 多核高并发处理 4core 0 - 0 core 1 - 1 2 -2 3 -3
CPU_ZERO(&cpu_affinity); // 结构体清零
// CPU_SETSIZE:1024 支持cpu最大的数量
CPU_SET(worker % CPU_SETSIZE, &cpu_affinity); // 0 1 2 3 设置核
/*
在多CPU系统中,通过sched_setaffinity ()可以设置进程的CPU亲和力,
使进程绑定在某一个或几个CPU上运行,避免在CPU之间来回切换,从而提高该进程的实时性能。
*/
if (sched_setaffinity(0, sizeof(cpu_set_t), &cpu_affinity) == -1)
{
fprintf(stderr, "sched_setaffinity() failed\n");
}
}
查看进程对应的核数

代码中函数指针不太理解的看看下方代码:
// typedef 返回类型(*新类型)(参数表)
typedef char (*PTRFUN)(int);
PTRFUN pFun;
char glFun(int a){ return;}
void main()
{
pFun = glFun;
(*pFun)(2); //调用函数
}
查看进程在cpu的核上执行的命令: ps -eLo ruser,pid,lwp,psr,args
一个父进程退出,而它的一个或多个子进程还在运行,那么那些子进程将成为孤儿进程。孤儿进程将被init进程所收养,并由init进程对它们完成状态收集工作。
想想我们如何模仿一个孤儿进程? 答案是: kill 父进程!
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
int main(){
int fpid = 1;// 父子进程不共享局部变量
for(int i = 5 ; i > 0 && fpid > 0 ; i--){
fpid = fork();
}
if(fpid < 0){
printf("创建子进程失败\n");
return fpid;
}else if(fpid == 0){
while(1);
}else if(fpid > 0){
while(1);
}
return 0;
}

把孤儿进程做成守护进程
不与任何终端关联的进程,通常情况下守护进程在系统启动时就在运行,它们以root用户或者其他特殊用户(apache和postfix)运行,并能处理一些系统级的任务。守护进程脱离于终端,是为了避免进程在执行过程中的信息在任何终端上显示,并且进程也不会被任何终端所产生的终端信息所打断(比如关闭终端等)。那如何成为一个守护进程呢? 步骤如下:
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
// 一般传入 0 , 0
int daemon(int nochdir, int noclose)
{
int fd = 0;
switch (fork())
{
case -1:
return (-1);
case 0:
break;
default:
_exit(0); // 父进程自杀
}
if (setsid() == -1) // 创建会画
return (-1);
if (!nochdir) // 将当前目录改成根目录
(void)chdir("/");
if (!noclose && (fd = open("/dev/null", O_RDWR, 0)) != -1)
{
// 重定向 标准输入 标准输出 标准出错
(void)dup2(fd, STDIN_FILENO);
(void)dup2(fd, STDOUT_FILENO);
(void)dup2(fd, STDERR_FILENO);
if (fd > 2)
(void)close(fd);
}
return (0);
}
int main()
{
// 创建子进程,并且把父进程杀死
daemon(0,0);
printf("hello\n");
while(1);// 处理事务
return 0;
}
父进程自杀后,守护进程 init 接管 , 一直在后台进行运行

一个进程使用fork创建子进程,如果子进程退出(exit),而父进程并没有调用wait或waitpid获取子进程的状态信息,那么子进程的进程描述符仍然保存在系统中。这种进程称之为僵死进程。
1.怎么查看僵尸进程:
利用命令ps,可以看到有标记为的进程就是僵尸进程。
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>
int main(){
pid_t fpid = fork();
if(fpid < 0){
printf("创建子进程失败\n");
return fpid;
}else if(fpid == 0){
exit(-1);
}else if(fpid > 0){
while(1);
}
return 0;
}
这里可以用 wait 和 waitpid 函数回收子进程

2.怎样来清除僵尸进程:
在MRIRuby中我可以这样做:deftransferinternal_server=self.init_serverpid=forkdointernal_server.runend#Maketheserverprocessrunindependently.Process.detach(pid)internal_client=self.init_client#Dootherstuffwithconnectingtointernal_server...internal_client.post('somedata')ensure#KillserverProcess.kill('KILL',
我正在编写一个gem,我必须在其中fork两个启动两个webrick服务器的进程。我想通过基类的类方法启动这个服务器,因为应该只有这两个服务器在运行,而不是多个。在运行时,我想调用这两个服务器上的一些方法来更改变量。我的问题是,我无法通过基类的类方法访问fork的实例变量。此外,我不能在我的基类中使用线程,因为在幕后我正在使用另一个不是线程安全的库。所以我必须将每个服务器派生到它自己的进程。我用类变量试过了,比如@@server。但是当我试图通过基类访问这个变量时,它是nil。我读到在Ruby中不可能在分支之间共享类变量,对吗?那么,还有其他解决办法吗?我考虑过使用单例,但我不确定这是
我正在尝试使用以下代码通过将ffmpeg实用程序作为子进程运行并获取其输出并解析它来确定视频分辨率:IO.popen'ffmpeg-i'+path_to_filedo|ffmpegIO|#myparsegoeshereend...但是ffmpeg输出仍然连接到标准输出并且ffmepgIO.readlines是空的。ffmpeg实用程序是否需要一些特殊处理?或者还有其他方法可以获得ffmpeg输出吗?我在WinXP和FedoraLinux下测试了这段代码-结果是一样的。 最佳答案 要跟进mouviciel的评论,您需要使用类似pope
我目前正在用Ruby编写一个项目,它使用ActiveRecordgem进行数据库交互,我正在尝试使用ActiveRecord::Base.logger记录所有数据库事件具有以下代码的属性ActiveRecord::Base.logger=Logger.new(File.open('logs/database.log','a'))这适用于迁移等(出于某种原因似乎需要启用日志记录,因为它在禁用时会出现NilClass错误)但是当我尝试运行包含调用ActiveRecord对象的线程守护程序的项目时脚本失败并出现以下错误/System/Library/Frameworks/Ruby.frame
我想从rubyrake脚本运行一个可执行文件,比如foo.exe我希望将foo.exe的STDOUT和STDERR输出直接写入我正在运行rake任务的控制台.当进程完成时,我想将退出代码捕获到一个变量中。我如何实现这一目标?我一直在玩backticks、process.spawn、system但我无法获得我想要的所有行为,只有部分更新:我在Windows上,在标准命令提示符下,而不是cygwin 最佳答案 system获取您想要的STDOUT行为。它还返回true作为零退出代码,这可能很有用。$?填充了有关最后一次system调
A/ctohttp://wiki.nginx.org/CoreModule#usermaster进程曾经以root用户运行,是否可以以不同的用户运行nginxmaster进程? 最佳答案 只需以非root身份运行init脚本(即/etc/init.d/nginxstart),就可以用不同的用户运行nginxmaster进程。如果这真的是你想要做的,你将需要确保日志和pid目录(通常是/var/log/nginx&/var/run/nginx.pid)对该用户是可写的,并且您所有的listen调用都是针对大于1024的端口(因为绑定(
我有一个应用程序正在从Ruby迁移到JRuby(由于需要通过Java提供更好的Web服务安全支持)。我使用的gem之一是daemons创建后台作业。问题在于它使用fork+exec来创建后台进程,但这对JRuby来说是禁忌。那么-是否有用于创建后台作业的替代gem/wrapper?我目前的想法是只从shell脚本调用rake并让rake任务永远运行......提前致谢,克里斯。更新我们目前正在使用几个与Java线程相关的包装器,即https://github.com/jmettraux/rufus-scheduler和https://github.com/philostler/acts
在尝试实现应用auto_orient的过程之后!对于我的图片,我收到此错误:ArgumentError(noimagesinthisimagelist):app/uploaders/image_uploader.rb:36:in`fix_exif_rotation'app/controllers/posts_controller.rb:12:in`create'Carrierwave在没有进程的情况下工作正常,但在添加进程后尝试上传图像时抛出错误。流程如下:process:fix_exif_rotationdeffix_exif_rotationmanipulate!do|image|
我有一个将某些事件写入队列的Rails3应用。现在我想在服务器上创建一个服务,每x秒轮询一次队列,并按计划执行其他任务。除了创建ruby脚本并通过cron作业运行它之外,还有其他稳定的替代方案吗? 最佳答案 尽管启动基于Rails的持久任务是一种选择,但您可能希望查看更有序的系统,例如delayed_job或Starling管理您的工作量。我建议不要在cron中运行某些东西,因为启动整个Rails堆栈的开销可能很大。每隔几秒运行一次它是不切实际的,因为Rails上的启动时间通常为5-15秒,具体取决于您的硬件。不过,每天这样做几
已检查ActiveRecord、DataMapper、Sequel:有些使用全局变量(静态变量)有些需要在使用模型加载源文件之前打开数据库连接。在使用不同数据库的sinatra应用程序中使用哪种ORM更好。 最佳答案 DataMapper专为多数据库使用而设计。你可以通过像DataMapper.setup(:repository_one,"mysql://localhost/my_db_name")这样的方式设置多个存储库。DataMapper随后会跟踪所有已在哈希中设置的存储库,您可以引用该哈希并将其用于范围界定:DataMapp