前面介绍了父子进程,如果当多个进程企图对共享数据进行处理。而最后的结果又取决于进程运行的顺序时,就认为发生了竞争关系。通过下面的例子来看下

在这里标准输出被设置为不带缓冲的,于是父子进程每输出一个字符就要进行一次write调用。这样做的目的是尽可能多次地在两个进程之间进行切换,以便演示竞争条件。

static void charatatime(char *str){

char *ptr;

int c;

setbuf(stdout,NULL);

for(ptr=str;(c=*ptr++)!=’\0‘;)

putc(c,stdout);

}

void competition(){

pid_t pid;

if ((pid=fork()) < 0){

printf("error");

}

else if(pid == 0){

charatatime("output from child\n");

}

else{

charatatime("output from parent\n");

}

exit(0);

}

来看下系统运行的结果:

第一次:

第二次:

第三次:

通过三次运行结果来看,除了第一次运行正常外,其他两次的字符都是杂乱的。原因就在于父子进程启动的顺序是有先有后的。

为了避免竞争条件,在多个进程之间需要有某种形式的信号发送和接收的方式。在linux中可以使用信号机制。具体实现方法如下

#include <stdio.h>

#include <stdlib.h>

#include <unistd.h>

#include <sys/wait.h>

#include <fcntl.h>

#include <signal.h>

#include <sys/types.h>

static volatile sig_atomic_t sigflag;

static sigset_t newmask, oldmask, zeromask;

/* signal handler for SIGUSR1 and SIGUSR2 */

static void sig_usr(int signo)

{

sigflag = 1;

return;

}

void TELL_WAIT()

{

if(signal(SIGUSR1, sig_usr) == SIG_ERR)

printf("signal SIGUSR1 error\n");

if(signal(SIGUSR2, sig_usr) == SIG_ERR)

printf("signal SIGUSR2 error\n");

sigemptyset(&zeromask);

sigemptyset(&newmask);

sigaddset(&newmask, SIGUSR1);

sigaddset(&newmask, SIGUSR2);

/* block SIGUSR1 and SIGUSR2, and save current signal mask */

if(sigprocmask(SIG_BLOCK, &newmask, &oldmask) < 0)

printf("SIG_BLOCK error\n");

}

void TELL_PARENT(pid_t pid)

{

kill(pid, SIGUSR2); /* tell parent we are done */

}

void WAIT_PARENT()

{

while(sigflag == 0)

sigsuspend(&zeromask); /* wait for parent */

sigflag = 0;

/* reset signal mask */

if(sigprocmask(SIG_SETMASK, &oldmask, NULL) < 0)

printf("SIG_SETMASK error\n");

}

void TELL_CHILD(pid_t pid)

{

kill(pid, SIGUSR1);

}

void WAIT_CHILD()

{

while(sigflag == 0)

sigsuspend(&zeromask); /* wait for parent */

sigflag = 0;

/* reset signal mask */

if(sigprocmask(SIG_SETMASK, &oldmask, NULL) < 0)

printf("SIG_SETMASK error\n");

}

void do_task(char *task_str)

{

printf("%s\n", task_str);

}

那么在之前的代码更新如下:

oid competition(){

pid_t pid;

TELL_WAIT();

if ((pid=fork()) < 0){

printf("error");

}

else if(pid == 0){

WAIT_PARENT();  //等待父进程先进行

charatatime("output from child\n");

}

else{

charatatime("output from parent\n");

TELL_CHILD(pid); //告诉子进程运行

}

exit(0);

}

此时运行的顺序就会固定。也不会出现杂乱的字符。

linux c编程:进程控制(二)_竞争条件的更多相关文章

  1. Unix环境高级编程—进程控制(二)

    一.函数wait和waitpid 今天我们继续通过昨天那个死爹死儿子的故事来讲(便于记忆),现在看看wait和waitpid函数. #include<sys/wait.h> pid_t w ...

  2. Linux系统编程@进程通信(一)

    进程间通信概述 需要进程通信的原因: 数据传输 资源共享 通知事件 进程控制 Linux进程间通信(IPC)发展由来 Unix进程间通信 基于System V进程间通信(System V:UNIX系统 ...

  3. Linux系统编程@进程管理(一)

    课程目标: 构建一个基于主机系统的多客户即时通信/聊天室项目 涉及的理论知识 进程控制:僵尸进程/孤儿进程.进程控制.守护进程... 进程间通信:管道.命名管道.信号... 多线程编程: 锁.信号量. ...

  4. Linux C 程序 进程控制(17)

    进程控制 1.进程概述现代操作系统的特点在于程序的并行执行.Linux是一个多用户多任务的操作系统.ps .pstree 查看进程进程除了进程id外还有一些其他标识信息,可以通过相应的函数获得.// ...

  5. linux 命令及进程控制

    main.c  main.o/main.obj  main/main.exe          编译                连接 程序运行;      两步: gcc/g++  -c  mai ...

  6. [linux] C语言Linux系统编程进程基本概念

    1.如果说文件是unix系统最重要的抽象概念,那么进程仅次于文件.进程是执行中的目标代码:活动的.生存的.运行的程序. 除了目标代码进程还包含数据.资源.状态以及虚拟化的计算机. 2.进程体系: 每一 ...

  7. linux系统编程-进程

    进程 现实生活中 在很多的场景中的事情都是同时进行的,比如开车的时候 手和脚共同来驾驶汽车,再比如唱歌跳舞也是同时进行的: 如下是一段视频,迈克杰克逊的一段视频: http://v.youku.com ...

  8. linux与Windows进程控制

    进程管理控制 这里实现的是一个自定义timer用于统计子进程运行的时间.使用方式主要是 timer [-t seconds] command arguments 例如要统计ls的运行时间可以直接输入t ...

  9. linux系统调用之进程控制

    1 进程控制: fork                                                                                     创建一 ...

随机推荐

  1. win10 如何配置 java jdk1.8环境变量(2017.8.17 )jdk1.8.0_144

    win10 如何配置 java jdk 环境变量 2017.8.17 本篇还适用于 windows server 2012. windows server 2014+ 一.安装 下载 jdk 64位 ...

  2. linux下编译C/C++

    对所有用户有效在/etc/profile增加以下内容.只对当前用户有效在Home目录下的.bashrc或.bash_profile里增加下面的内容:(注意:等号前面不要加空格,否则可能出现 comma ...

  3. hbuilder - wap to app

    官方文档: http://www.dcloud.io/wap2app.html 新建Wap2App,示例网址:www.baidu.com 随后,我们可以在 最后,我们可以 打包完成以后,下载即可

  4. Linux——Django 开发环境部署(一)

    Django 开发环境部署(一) 之所以 写这篇文章的原因在于django环境的确轻松搭建,之前Ubuntu上安装了,的确很轻松,但是后期我才知道随便做个环境出来很容易到了后面很麻烦,污 染了系统里的 ...

  5. 跟踪运行时错误 vue

    如果在组件渲染时出现运行错误,错误将会被传递至全局 Vue.config.errorHandler 配置函数 (如果已设置).利用这个钩子函数来配合错误跟踪服务是个不错的主意.比如 Sentry,它为 ...

  6. 自上而下渐显图片的CSS3实现

    代码地址如下:http://www.demodashi.com/demo/12160.html 目录 一.实现思路 二.所用特性 三.示例代码 四.实例效果 五.组件化(Vue) 一.实现思路 从效果 ...

  7. NoSQL之Redis学习小结

    大数据时代要求: 三V:Volume海量.Velocity实时.Variety多样: 三高:高并发.高可扩.高性能 高并发操作不建议使用关联查询,而使用冗余数据,分布式系统支持不了太多的并发. 横向 ...

  8. unity4.6 Beta版 UI控件之Button

    近期需求,须要用到4.6版本号uGui了,所以抽时间来学习学习,就UI控件在Unity工具里创建预设这块来说相比較于NGUI,我认为是没有什么太大的差别的. 比方:Canvas--Camera . T ...

  9. sprint3 【每日scrum】 TD助手站立会议第八天

    站立会议 组员 昨天 今天 困难 签到 刘铸辉 (组长) 调整闹钟和整个项目的显示效果,最后做出了微信界面滑动的显示效果 整合原来做过的功能,并做相应的改进,整合其他的功能 在界面的设计和用户交互上始 ...

  10. Memcached的LRU和缓存命中率

    缓存命中率 命中:直接从缓存中读取到想要的数据. 未中:缓存中没有想要的数据,还需要到数据库进行一次查询才能读取到想要的数据. 命中率越高,数据库查询的次数就越少. 读取缓存的速度远比数据库查询的速度 ...