linux c编程:进程控制(二)_竞争条件
前面介绍了父子进程,如果当多个进程企图对共享数据进行处理。而最后的结果又取决于进程运行的顺序时,就认为发生了竞争关系。通过下面的例子来看下
在这里标准输出被设置为不带缓冲的,于是父子进程每输出一个字符就要进行一次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编程:进程控制(二)_竞争条件的更多相关文章
- Unix环境高级编程—进程控制(二)
一.函数wait和waitpid 今天我们继续通过昨天那个死爹死儿子的故事来讲(便于记忆),现在看看wait和waitpid函数. #include<sys/wait.h> pid_t w ...
- Linux系统编程@进程通信(一)
进程间通信概述 需要进程通信的原因: 数据传输 资源共享 通知事件 进程控制 Linux进程间通信(IPC)发展由来 Unix进程间通信 基于System V进程间通信(System V:UNIX系统 ...
- Linux系统编程@进程管理(一)
课程目标: 构建一个基于主机系统的多客户即时通信/聊天室项目 涉及的理论知识 进程控制:僵尸进程/孤儿进程.进程控制.守护进程... 进程间通信:管道.命名管道.信号... 多线程编程: 锁.信号量. ...
- Linux C 程序 进程控制(17)
进程控制 1.进程概述现代操作系统的特点在于程序的并行执行.Linux是一个多用户多任务的操作系统.ps .pstree 查看进程进程除了进程id外还有一些其他标识信息,可以通过相应的函数获得.// ...
- linux 命令及进程控制
main.c main.o/main.obj main/main.exe 编译 连接 程序运行; 两步: gcc/g++ -c mai ...
- [linux] C语言Linux系统编程进程基本概念
1.如果说文件是unix系统最重要的抽象概念,那么进程仅次于文件.进程是执行中的目标代码:活动的.生存的.运行的程序. 除了目标代码进程还包含数据.资源.状态以及虚拟化的计算机. 2.进程体系: 每一 ...
- linux系统编程-进程
进程 现实生活中 在很多的场景中的事情都是同时进行的,比如开车的时候 手和脚共同来驾驶汽车,再比如唱歌跳舞也是同时进行的: 如下是一段视频,迈克杰克逊的一段视频: http://v.youku.com ...
- linux与Windows进程控制
进程管理控制 这里实现的是一个自定义timer用于统计子进程运行的时间.使用方式主要是 timer [-t seconds] command arguments 例如要统计ls的运行时间可以直接输入t ...
- linux系统调用之进程控制
1 进程控制: fork 创建一 ...
随机推荐
- Solidworks如何在自定义的基准面上创建3D草图
1 选择某个基准面 右击"基准面上的3D草图" 2 当基准面出现黄色框即为正确.
- [CSS3]移动Web开发系列之CSS3增强型选择器
css3是移动Web开发的主要技术之中的一个.当前.CSS3技术最适合在移动Web开发中使用的特性有增强的选择器.阴影.强大的背景设置 .圆角边框 接下来我们主要解说增强型的选择器.主要分两种,属性选 ...
- 基于Saltstatck实现页面实时显示tomcat启动日志(17)
一.相关文件 master端: /srv/salt/tomcat/start.sls #tomcat启动服务state.sls,须要自己创建 /srv/salt/tomca ...
- JavaScript历史状态管理
1.API (1)history.pushState:能够在不加载新页面的情况下改变浏览器的 URL history.pushState({name:"Nicholas"}, &q ...
- 微信小程序登录JAVA后台
代码地址如下:http://www.demodashi.com/demo/12736.html 登录流程时序登录流程时序 具体的登录说明查看 小程序官方API 项目的结构图: springboot项目 ...
- redis 的安装与启动
1.redis介绍 Redis是一个开源的使用ANSI C语言编写.支持网络.可基于内存亦可持久化的日志型.Key-Value数据库,并提供多种语言的API. Redis 是一个高性能的key-val ...
- 使用eclipse开发hbase程序
一:在eclipse创建一个普通的java项目 二:新建一个文件夹,把hbase需要的jar放进去,我这里把hbase/lib/*.jar 下所有的jar都放进去了,最后发现就用到了下面三个jar ...
- Junit 内部解密之二: TestResult + TestListener + Assert
转自:http://blog.sina.com.cn/s/blog_6cf812be0100wbhw.html 之前我们看到了Test接口里面的run方法有个TestResult的参数,不错,这个类就 ...
- Amzaon EC2虚拟化技术演进:从 Xen 到 Nitro
今年2月,由光环新网运营的 AWS 中国(北京)区域和由西云数据运营的 AWS 中国 (宁夏)区域发布新的实例类型,新的实例类型包括 C5.C5d.R5.R5d.除了这四种之外,在AWS国外部分区 ...
- [转]const指针与指向const的指针
经常忘记,保存一下.. #include <iostream> using namespace std; int main(int argc, char *argv[]) { ; int ...