- 浏览: 361923 次
- 性别:
最新评论
-
天使建站:
这里这篇文章更详细 还有完整的实例演示:js跳出循环:brea ...
js跳出循环的方法区别(break,continue,return) -
jahentao:
我觉得Jcreator和eclipse中的列出属性和方法,很多 ...
反射原理 -
T240178168:
相互交流下吧
ie9以下都有这个问题(ajax) -
blackproof:
试了一下,的确第一种写法oracle优化了,效率比第二种快多了 ...
Oracle分页sql语句 -
杨白白:
进程与线程
进程通信
(1)进程的同步与互斥
一般来说同步反映了进程之间的协作性质,往往指有几个进程共同完成一个任务时在时间次序上的某种限制,进程相互之间各自的存在及作用,通过交换信息完成通信。如接力比赛中一组队员使用接力棒等。
进程互斥体现了进程之间对资源的竞争关系,这时进程相互之间不一定清楚其它进程情况,往往指多个任务多个进程间的通讯制约,因而使用更广泛。如打篮球时双方挣抢篮板球等。
(2)临界区
并发进程中与共享变量有关的程序段定义为临界区。进入临界区的准则是:①一次只准一个进程进入临界区;②本进程结束负责通知下一进程;③进程调度,不能阻塞。
(3)原语
原语是不可中断的过程。
·加锁/开锁(LOCK/UNLOCK)原语
优点是实现互斥简单;缺点是效率很低。
·信号量(Semaphore)及PV操作
PV操作能够实现对临界区的管理要求。它由P操作原语和V操作原语组成,对信号量进行操作,具体定义如下:
P(S):①将信号量S的值减1,即S=S-1;
②如果S>0,则该进程继续执行;否则该进程置为等待状态,排入等待队列。
V(S):①将信号量S的值加1,即S=S+1;
②如果S<=0,则该进程继续执行;否则释放队列中第一个等待信号量的进程。
信号量的数据结构为一个值和一个指针,指针指向等待该信号量的下一个进程。信号量的值与相应资源的使用情况有关。当它的值大于0时,表示当前可用资源的数量;当它的值小于0时,其绝对值表示等待使用该资源的进程个数。注意信号量的值仅能由PV操作来改变。
一般来说,信号量S0时,S表示可用资源的数量。执行一次P操作意味着请求分配一个单位资源,因此S的值减1;当S<0时,表示已经没有可用资源,请求者必须等待别的进程释放该类资源,它才能运行下去。而执行一个V操作意味着释放一个单位资源,因此S的值加1;若S0,表示有某些进程正在等待该资源,因此要唤醒一个等待状态的进程,使之运行下去。
消息缓冲通信原语
高级通信原语,用于一组信息发送(Send)与读取(Read)。
生产者-消费者问题:
在这个问题上主要考虑的是:缓冲区满或缓冲区空以及竞争条件(race condition)。以下是一个含竞争条件的生产者-消费者问题实例。
#define N 100 /*number of slots in the buffer*/
int count=0; /*number of items in the buffer*/
void producer(void) {
int item;
while(TRUE) {
produce_item(&item);
if (count==N) sleep();
enter_item(item);
count=count+1;
if (count==1) wakeup(consumer);
}
}
void comsumer(void) {
int item;
while(TRUE) {
if(count==0) sleep();
remove_item(&item);
count=count-1;
if (count==N-1) wakeup(producer);
consume_item(item);
}
}
信号量的概念首先由E.W.Dijkstra在1965年提出的。semaphore(信号量)是一个大于等于零的整型变量。 对信号量有两个原子操作:-和+,DOWN()和UP(),SLEEP()和WAKEUP(),P()和V(),Wait() 和Signal()。虽然它们名字都不一样,可意思都是相同的,拿down和up操作来说明。 DOWN(t)操作 递减信号量t的值:先检查t是否大于0,若t大于0则t减去1;若t的值为0,则进程进入睡眠状态,而此时的DOWN操作并没有结束。这是原子操作,用来保证一旦一个信号量的操作开始,则在操作完成或阻塞之前别的进程不允许访问该信号量。 UP(t)操作 递增信号量t的值:如果一个或多个进程在该信号量t上睡眠,则无法完成一个先前的DOWN操作,则由系统选择其中的一个并允许起完成它的DOWN操作。因此,对一个有进程在起上睡眠的信号量执行一次UP操作以后,该信号量的值仍旧是0,但在其上睡眠的进程却少了一个。递增信号量的值和唤醒一个进程的操作也是原子操作,不可分割的。这样做保证不会有进程因为执行UP操作而被阻塞。
多线程程序中最简单也是最常用的同步机制要算是mutex(互斥量)。
一个mutex提供两个基本操作:DOWN和UP。一旦某个线程调用了DOWN,其它线程再调用DOWN时就会被阻塞。当这个线程调用UP后,刚才阻塞在DOWN里的线程中,会有一个且仅有一个被唤醒。换句话说,对于一个给定的mutex,只有一个线程可以在DOWN和UP调用之间获取处理器时间。这里的mutex 用来保护访问的临界区,避免数据出现竞争条件。
#include<sys/types.h>
#include<linux/sem.h>
#include<linux/shm.h>
#include<unistd.h>
#include<stdio.h>
#include<errno.h>
#include<time.h>
#define MAXSHM 5 //定义缓冲区数组的下标变量个数
/* 定义3个信号量的内部标识 */
int fullid;
int emptyid;
int mutexid;
/* 主函数 */
int main()
{
/* 定义2个共享内存的ID */
int arrayid;
int getid;
/* 定义共享内存虚拟地址 */
int *array;
int *get;
/* 创建共享内存 */
arrayid=shmget(IPC_PRIVATE,sizeof(int) *MAXSHN,IPC_CREAT|0666);
getid=shmget(IPC_PRIVATE,sizeof(int),IPC_CREAT|0666);
/* 初始化共享内存 */
array=(int *) shmat(arrayid,0,0);
get=(int *) shmat(getid,0,0);
*get=0;
/* 定义信号量数据结构 */
struct sembuf P,V;
union semun arg;
/* 创建信号量 */
fullid=semget(IPC_PRIVATE,1,IPC_CREAT|0666);
emptyid=semget(IPC_PRIVATE,1,IPC_CREAT|0666);
mutexid=semget(IPC_PRIVATE,1,IPC_CREAT|0666);
/*初始化信号量 */
arg.val=0; //初始时缓冲区中无数据
if(semctl(fullid,0,SETVAL,arg)==-1)
perror("semctl setval error");
arg.val=MAXSHM; //初始时缓冲区中有5个空闲的数组元素
if(semctl(emptyid,0,SETVAL,arg)==-1)
perror("semctl setval error");
arg.val=1; //初始时互斥信号为1,允许一个进程进入
if(semctl(mutexid,0,SETVAL,arg)==-1)
perror("semctl setval error");
/* 初始化 P V操作 */
P.sem_num=0;
P.sem_op=-1;
P.sem_flg=SEM_UNDO;
V.sem_num=0;
V.sem_op=1;
V.sem_flg=SEM_UNDO;
/* 生产者进程 */
if(fork()==0)
{
int i=0;
int set=0;
while(i<10)
{
semop(emptyid,&P,1); //对 emptyid执行P操作
semop(mutexid,&P,1); //对 mutexid执行 P操作
array[set%MAXSHM]=i+1;
printf("Producer put number %d to No.%d\n",array[set%MAXSHM],set%MAXSHM);
set++; //写计数加1
semop(mutexid,&V,1); //对mutexid执行 V 操作
semop(fullid,&V,1); //对fullid执行 V 操作
i++;
}
sleep(3); //SLEEP 3秒,等待消费者进程执行完毕
printf("Poducer if over\n");
exit(0);
}
else
{
/* 消费者A进程 */
if(fork()==0)
{
while(1)
{
if(*get==10)
break;
semop(fullid,&P,1); //对fullid执行 P 操作
semop(mutexid,&P,1); //对mutexid执行 P 操作
printf("The ConsumerA get number from No.%d\n",(*get)%MAXSHM);
(*get)++; //读计数加1
semop(mutexid,&V,1); //对mutexid执行 V 操作
semop(emptyid,&V,1); //对fullid执行 V 操作
sleep(1);
}
printf("ConsunerA is over\n");
exit(0);
}
else
{
/*消费者B进程 */
if(fork()==0)
{
while(1)
{
if(*get==10)
break;
semop(fullid,&P,1); //对fullid执行 P 操作
semop(mutexid,&P,1); //对mutexid执行 P 操作
printf("The ConsumerA get number from No.%d\n",(*get)%MAXSHM);
(*get)++; //读计数加1
semop(mutexid,&V,1); //对mutexid执行 V 操作
semop(emptyid,&V,1); //对emptyid执行 V 操作
sleep(1);
}
printf("ConsunerB is over\n");
exit(0);
}
}
}
/* 父进程返回后回收3个子进程 */
wait(0);
wait(0);
wait(0);
/* 断开并撤消2个共享内存 */
shmdt(array);
shmctl(arrayid,IPC_RMID,0);
shmctl(get);
shmctl(getid,IPC_RMID,0);
/* 撤消3个信号量集 */
semctl(emptyid,IPC_RMID,0);
semctl(fullid,IPC_RMID,0);
semctl(mutexid,IPC_RMID,0);
exit(0);
}
主要函数及数据结构:
signal();//安装信号用。signalaction 也可以,但好像太繁,小程序不用
sigxxxset();//信号集操作
sigprocmask();//设置信号集
sigsuspend();//等待相关信号
代码:
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <signal.h>
void wake(){ return;}//do nothing but return immediately to wake up the process
int main()
{
sigset_t set;
pid_t pid;
int i;
sigfillset(&set);
sigdelset(&set,SIGINT);
sigprocmask(SIG_SETMASK,&set,NULL);//for user control
if( (pid=fork() ) ==0 )//child
{
sigdelset(&set,SIGUSR2);
signal(SIGUSR2,wake);//install the child handler
sleep(1);
puts("This is child. I am going to wake parent first.");
for( i=1;i<=4;i++)
{
kill(getppid(),SIGUSR1);//send singal to parent
sigsuspend(&set);//waiting for parent's signal
puts("Parent wake me up!");
/*
critical code
*/
printf("Child: i=%d.\n",i);
}
_exit(0);
}
//parent
sigdelset(&set,SIGUSR1);
signal(SIGUSR1,wake);
puts("I am the parent!");
for( i=1;i<=4;i++)
{
sigsuspend(&set);//waiting for child's signal
puts("Child wake me up!");
/*
critical code
*/
printf("Parent: i=%d.\n",i);
kill(pid,SIGUSR2);//sending child signal
}
return 0;
}
运行结果:
I am the parent!
This is child. I am going to wake parent first.
Child wake me up!
Parent: i=1.
Parent wake me up!
Child: i=1.
Child wake me up!
Parent: i=2.
Parent wake me up!
Child: i=2.
Child wake me up!
Parent: i=3.
Parent wake me up!
Child: i=3.
Child wake me up!
Parent: i=4.
Parent wake me up!
Child: i=4.
解释:
一开始把信号集填满并设置是为了避免没必要的信号的干扰。并且,在父子进程还没运行到要接受信号的地方时,互相受影响。当然,你如果把这一步省了你就会看到,运行结果不像你想像的那样了。
更复杂的延伸。利用信号进行数学计算控制。实质上,这里可以搞并行计算的(smp required)。但只是为了简单,所以没有写成并行而已。
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/shm.h>
#include <sys/types.h>
#include <signal.h>
#include <math.h>
double ac(double);
double bc(double,double);
double cc(double,double);
double dc(double,double);
void wake(){return;}
int main()
{
pid_t pid;
key_t key=ftok("/dev/shm/",3);
int shmid;
sigset_t set;
typedef struct
{
double a;
double b;
double c,d;
}data;
data* ptr;
sigfillset(&set);
sigdelset(&set,SIGINT);
sigprocmask(SIG_SETMASK,&set,NULL);
if( (shmid=shmget(key,sizeof(data),IPC_CREAT|0666)) == -1 )
{
perror("shmget fail");
exit(1);
}
if( (ptr=(data*)shmat(shmid,NULL,0)) == NULL)
{
perror("shmat fail");
exit(1);
}
ptr->a=1.0;
ptr->b=2.0;
if( (pid=fork() ) ==0)
{
sigdelset(&set,SIGUSR2);//parent will wake me up through this signal
signal(SIGUSR2,wake);
puts("\
Hello, this is the child! I will be sleeping\n\
until the parent finish the 1st part calculation.\n\
Then he will wake me up. Now, I go to bed!");
sigsuspend(&set);//waiting for parent's signal, because parent will send the first signal
ptr->b=bc(ptr->a,ptr->b);
puts("2nd part finished!");//actually, you don't need this.
kill(getppid(),SIGUSR1);//tell parent that he has done the jub
sigsuspend(&set);//waiting for the parent's wakeup again.
ptr->d=dc(ptr->b,ptr->c);
puts("4th part finished!");//actually, you don't need this.
puts("OK, the child has done his job!");
shmdt(ptr);
kill(getppid(),SIGUSR1);
_exit(0);
}
// parent now
sigdelset(&set,SIGUSR1);
signal(SIGUSR1,wake);
puts("Hello, this is parent!");
sleep(1);//let the user to read clearly
ptr->a=ac(ptr->a);//calculate the first part
puts("first part finished!");//actually, you don't need this.
kill(pid,SIGUSR2);
sigsuspend(&set);
ptr->c=cc(ptr->a,ptr->b);
puts("3rd part finished!");//actually, you don't need this.
kill(pid,SIGUSR2);
sigsuspend(&set);
puts("OK, all the caculation has been done. The result is:");
printf("a=%f, b=%f, c=%f, d=%f.\n",ptr->a,ptr->b,ptr->c,ptr->d);
shmctl(shmid,IPC_RMID,NULL);
return 0;
}
double ac(double x)
{
return (sin(x)+cos(x)+tan(x) );
}
double bc(double x,double y)
{
return (tan(x)+sin(y)+tan(y) );
}
double cc(double x,double y)
{
return (atan(x)+tan(x)+cos(y) );
}
double dc(double x,double y)
{
return ( atan(x*y) );
}
运行结果:
[sody@longtem os]$ ./a.out
Hello, this is the child! I will be sleeping
until the parent finish the 1st part calculation.
Then he will wake me up. Now, I go to bed!
Hello, this is parent!
first part finished!
2nd part finished!
3rd part finished!
4th part finished!
OK, the child has done his job!
OK, all the caculation has been done. The result is:
a=2.939181, b=-1.480964, c=1.127340, d=-1.031139.
(1)进程的同步与互斥
一般来说同步反映了进程之间的协作性质,往往指有几个进程共同完成一个任务时在时间次序上的某种限制,进程相互之间各自的存在及作用,通过交换信息完成通信。如接力比赛中一组队员使用接力棒等。
进程互斥体现了进程之间对资源的竞争关系,这时进程相互之间不一定清楚其它进程情况,往往指多个任务多个进程间的通讯制约,因而使用更广泛。如打篮球时双方挣抢篮板球等。
(2)临界区
并发进程中与共享变量有关的程序段定义为临界区。进入临界区的准则是:①一次只准一个进程进入临界区;②本进程结束负责通知下一进程;③进程调度,不能阻塞。
(3)原语
原语是不可中断的过程。
·加锁/开锁(LOCK/UNLOCK)原语
优点是实现互斥简单;缺点是效率很低。
·信号量(Semaphore)及PV操作
PV操作能够实现对临界区的管理要求。它由P操作原语和V操作原语组成,对信号量进行操作,具体定义如下:
P(S):①将信号量S的值减1,即S=S-1;
②如果S>0,则该进程继续执行;否则该进程置为等待状态,排入等待队列。
V(S):①将信号量S的值加1,即S=S+1;
②如果S<=0,则该进程继续执行;否则释放队列中第一个等待信号量的进程。
信号量的数据结构为一个值和一个指针,指针指向等待该信号量的下一个进程。信号量的值与相应资源的使用情况有关。当它的值大于0时,表示当前可用资源的数量;当它的值小于0时,其绝对值表示等待使用该资源的进程个数。注意信号量的值仅能由PV操作来改变。
一般来说,信号量S0时,S表示可用资源的数量。执行一次P操作意味着请求分配一个单位资源,因此S的值减1;当S<0时,表示已经没有可用资源,请求者必须等待别的进程释放该类资源,它才能运行下去。而执行一个V操作意味着释放一个单位资源,因此S的值加1;若S0,表示有某些进程正在等待该资源,因此要唤醒一个等待状态的进程,使之运行下去。
消息缓冲通信原语
高级通信原语,用于一组信息发送(Send)与读取(Read)。
生产者-消费者问题:
在这个问题上主要考虑的是:缓冲区满或缓冲区空以及竞争条件(race condition)。以下是一个含竞争条件的生产者-消费者问题实例。
#define N 100 /*number of slots in the buffer*/
int count=0; /*number of items in the buffer*/
void producer(void) {
int item;
while(TRUE) {
produce_item(&item);
if (count==N) sleep();
enter_item(item);
count=count+1;
if (count==1) wakeup(consumer);
}
}
void comsumer(void) {
int item;
while(TRUE) {
if(count==0) sleep();
remove_item(&item);
count=count-1;
if (count==N-1) wakeup(producer);
consume_item(item);
}
}
信号量的概念首先由E.W.Dijkstra在1965年提出的。semaphore(信号量)是一个大于等于零的整型变量。 对信号量有两个原子操作:-和+,DOWN()和UP(),SLEEP()和WAKEUP(),P()和V(),Wait() 和Signal()。虽然它们名字都不一样,可意思都是相同的,拿down和up操作来说明。 DOWN(t)操作 递减信号量t的值:先检查t是否大于0,若t大于0则t减去1;若t的值为0,则进程进入睡眠状态,而此时的DOWN操作并没有结束。这是原子操作,用来保证一旦一个信号量的操作开始,则在操作完成或阻塞之前别的进程不允许访问该信号量。 UP(t)操作 递增信号量t的值:如果一个或多个进程在该信号量t上睡眠,则无法完成一个先前的DOWN操作,则由系统选择其中的一个并允许起完成它的DOWN操作。因此,对一个有进程在起上睡眠的信号量执行一次UP操作以后,该信号量的值仍旧是0,但在其上睡眠的进程却少了一个。递增信号量的值和唤醒一个进程的操作也是原子操作,不可分割的。这样做保证不会有进程因为执行UP操作而被阻塞。
多线程程序中最简单也是最常用的同步机制要算是mutex(互斥量)。
一个mutex提供两个基本操作:DOWN和UP。一旦某个线程调用了DOWN,其它线程再调用DOWN时就会被阻塞。当这个线程调用UP后,刚才阻塞在DOWN里的线程中,会有一个且仅有一个被唤醒。换句话说,对于一个给定的mutex,只有一个线程可以在DOWN和UP调用之间获取处理器时间。这里的mutex 用来保护访问的临界区,避免数据出现竞争条件。
#include<sys/types.h>
#include<linux/sem.h>
#include<linux/shm.h>
#include<unistd.h>
#include<stdio.h>
#include<errno.h>
#include<time.h>
#define MAXSHM 5 //定义缓冲区数组的下标变量个数
/* 定义3个信号量的内部标识 */
int fullid;
int emptyid;
int mutexid;
/* 主函数 */
int main()
{
/* 定义2个共享内存的ID */
int arrayid;
int getid;
/* 定义共享内存虚拟地址 */
int *array;
int *get;
/* 创建共享内存 */
arrayid=shmget(IPC_PRIVATE,sizeof(int) *MAXSHN,IPC_CREAT|0666);
getid=shmget(IPC_PRIVATE,sizeof(int),IPC_CREAT|0666);
/* 初始化共享内存 */
array=(int *) shmat(arrayid,0,0);
get=(int *) shmat(getid,0,0);
*get=0;
/* 定义信号量数据结构 */
struct sembuf P,V;
union semun arg;
/* 创建信号量 */
fullid=semget(IPC_PRIVATE,1,IPC_CREAT|0666);
emptyid=semget(IPC_PRIVATE,1,IPC_CREAT|0666);
mutexid=semget(IPC_PRIVATE,1,IPC_CREAT|0666);
/*初始化信号量 */
arg.val=0; //初始时缓冲区中无数据
if(semctl(fullid,0,SETVAL,arg)==-1)
perror("semctl setval error");
arg.val=MAXSHM; //初始时缓冲区中有5个空闲的数组元素
if(semctl(emptyid,0,SETVAL,arg)==-1)
perror("semctl setval error");
arg.val=1; //初始时互斥信号为1,允许一个进程进入
if(semctl(mutexid,0,SETVAL,arg)==-1)
perror("semctl setval error");
/* 初始化 P V操作 */
P.sem_num=0;
P.sem_op=-1;
P.sem_flg=SEM_UNDO;
V.sem_num=0;
V.sem_op=1;
V.sem_flg=SEM_UNDO;
/* 生产者进程 */
if(fork()==0)
{
int i=0;
int set=0;
while(i<10)
{
semop(emptyid,&P,1); //对 emptyid执行P操作
semop(mutexid,&P,1); //对 mutexid执行 P操作
array[set%MAXSHM]=i+1;
printf("Producer put number %d to No.%d\n",array[set%MAXSHM],set%MAXSHM);
set++; //写计数加1
semop(mutexid,&V,1); //对mutexid执行 V 操作
semop(fullid,&V,1); //对fullid执行 V 操作
i++;
}
sleep(3); //SLEEP 3秒,等待消费者进程执行完毕
printf("Poducer if over\n");
exit(0);
}
else
{
/* 消费者A进程 */
if(fork()==0)
{
while(1)
{
if(*get==10)
break;
semop(fullid,&P,1); //对fullid执行 P 操作
semop(mutexid,&P,1); //对mutexid执行 P 操作
printf("The ConsumerA get number from No.%d\n",(*get)%MAXSHM);
(*get)++; //读计数加1
semop(mutexid,&V,1); //对mutexid执行 V 操作
semop(emptyid,&V,1); //对fullid执行 V 操作
sleep(1);
}
printf("ConsunerA is over\n");
exit(0);
}
else
{
/*消费者B进程 */
if(fork()==0)
{
while(1)
{
if(*get==10)
break;
semop(fullid,&P,1); //对fullid执行 P 操作
semop(mutexid,&P,1); //对mutexid执行 P 操作
printf("The ConsumerA get number from No.%d\n",(*get)%MAXSHM);
(*get)++; //读计数加1
semop(mutexid,&V,1); //对mutexid执行 V 操作
semop(emptyid,&V,1); //对emptyid执行 V 操作
sleep(1);
}
printf("ConsunerB is over\n");
exit(0);
}
}
}
/* 父进程返回后回收3个子进程 */
wait(0);
wait(0);
wait(0);
/* 断开并撤消2个共享内存 */
shmdt(array);
shmctl(arrayid,IPC_RMID,0);
shmctl(get);
shmctl(getid,IPC_RMID,0);
/* 撤消3个信号量集 */
semctl(emptyid,IPC_RMID,0);
semctl(fullid,IPC_RMID,0);
semctl(mutexid,IPC_RMID,0);
exit(0);
}
主要函数及数据结构:
signal();//安装信号用。signalaction 也可以,但好像太繁,小程序不用
sigxxxset();//信号集操作
sigprocmask();//设置信号集
sigsuspend();//等待相关信号
代码:
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <signal.h>
void wake(){ return;}//do nothing but return immediately to wake up the process
int main()
{
sigset_t set;
pid_t pid;
int i;
sigfillset(&set);
sigdelset(&set,SIGINT);
sigprocmask(SIG_SETMASK,&set,NULL);//for user control
if( (pid=fork() ) ==0 )//child
{
sigdelset(&set,SIGUSR2);
signal(SIGUSR2,wake);//install the child handler
sleep(1);
puts("This is child. I am going to wake parent first.");
for( i=1;i<=4;i++)
{
kill(getppid(),SIGUSR1);//send singal to parent
sigsuspend(&set);//waiting for parent's signal
puts("Parent wake me up!");
/*
critical code
*/
printf("Child: i=%d.\n",i);
}
_exit(0);
}
//parent
sigdelset(&set,SIGUSR1);
signal(SIGUSR1,wake);
puts("I am the parent!");
for( i=1;i<=4;i++)
{
sigsuspend(&set);//waiting for child's signal
puts("Child wake me up!");
/*
critical code
*/
printf("Parent: i=%d.\n",i);
kill(pid,SIGUSR2);//sending child signal
}
return 0;
}
运行结果:
I am the parent!
This is child. I am going to wake parent first.
Child wake me up!
Parent: i=1.
Parent wake me up!
Child: i=1.
Child wake me up!
Parent: i=2.
Parent wake me up!
Child: i=2.
Child wake me up!
Parent: i=3.
Parent wake me up!
Child: i=3.
Child wake me up!
Parent: i=4.
Parent wake me up!
Child: i=4.
解释:
一开始把信号集填满并设置是为了避免没必要的信号的干扰。并且,在父子进程还没运行到要接受信号的地方时,互相受影响。当然,你如果把这一步省了你就会看到,运行结果不像你想像的那样了。
更复杂的延伸。利用信号进行数学计算控制。实质上,这里可以搞并行计算的(smp required)。但只是为了简单,所以没有写成并行而已。
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/shm.h>
#include <sys/types.h>
#include <signal.h>
#include <math.h>
double ac(double);
double bc(double,double);
double cc(double,double);
double dc(double,double);
void wake(){return;}
int main()
{
pid_t pid;
key_t key=ftok("/dev/shm/",3);
int shmid;
sigset_t set;
typedef struct
{
double a;
double b;
double c,d;
}data;
data* ptr;
sigfillset(&set);
sigdelset(&set,SIGINT);
sigprocmask(SIG_SETMASK,&set,NULL);
if( (shmid=shmget(key,sizeof(data),IPC_CREAT|0666)) == -1 )
{
perror("shmget fail");
exit(1);
}
if( (ptr=(data*)shmat(shmid,NULL,0)) == NULL)
{
perror("shmat fail");
exit(1);
}
ptr->a=1.0;
ptr->b=2.0;
if( (pid=fork() ) ==0)
{
sigdelset(&set,SIGUSR2);//parent will wake me up through this signal
signal(SIGUSR2,wake);
puts("\
Hello, this is the child! I will be sleeping\n\
until the parent finish the 1st part calculation.\n\
Then he will wake me up. Now, I go to bed!");
sigsuspend(&set);//waiting for parent's signal, because parent will send the first signal
ptr->b=bc(ptr->a,ptr->b);
puts("2nd part finished!");//actually, you don't need this.
kill(getppid(),SIGUSR1);//tell parent that he has done the jub
sigsuspend(&set);//waiting for the parent's wakeup again.
ptr->d=dc(ptr->b,ptr->c);
puts("4th part finished!");//actually, you don't need this.
puts("OK, the child has done his job!");
shmdt(ptr);
kill(getppid(),SIGUSR1);
_exit(0);
}
// parent now
sigdelset(&set,SIGUSR1);
signal(SIGUSR1,wake);
puts("Hello, this is parent!");
sleep(1);//let the user to read clearly
ptr->a=ac(ptr->a);//calculate the first part
puts("first part finished!");//actually, you don't need this.
kill(pid,SIGUSR2);
sigsuspend(&set);
ptr->c=cc(ptr->a,ptr->b);
puts("3rd part finished!");//actually, you don't need this.
kill(pid,SIGUSR2);
sigsuspend(&set);
puts("OK, all the caculation has been done. The result is:");
printf("a=%f, b=%f, c=%f, d=%f.\n",ptr->a,ptr->b,ptr->c,ptr->d);
shmctl(shmid,IPC_RMID,NULL);
return 0;
}
double ac(double x)
{
return (sin(x)+cos(x)+tan(x) );
}
double bc(double x,double y)
{
return (tan(x)+sin(y)+tan(y) );
}
double cc(double x,double y)
{
return (atan(x)+tan(x)+cos(y) );
}
double dc(double x,double y)
{
return ( atan(x*y) );
}
运行结果:
[sody@longtem os]$ ./a.out
Hello, this is the child! I will be sleeping
until the parent finish the 1st part calculation.
Then he will wake me up. Now, I go to bed!
Hello, this is parent!
first part finished!
2nd part finished!
3rd part finished!
4th part finished!
OK, the child has done his job!
OK, all the caculation has been done. The result is:
a=2.939181, b=-1.480964, c=1.127340, d=-1.031139.
发表评论
-
UML类图与类的关系详解-UML一波流系列
2016-12-11 20:23 629http://peterwei.iteye.com/blog/ ... -
201612-8笔记
2016-12-08 22:46 543数据库设计 1.主表明确 主表一直是主,里面不需要关联关系 ... -
OOP和AOP区别
2015-04-27 17:18 3382OOP(面向对象编程)针对业务处理过程的实体及其属性和行为进行 ... -
正则表达式的基础语法
2015-01-06 23:08 762首先让我们看两个特殊 ... -
Filter过滤器在Web.xml中几个标签说明
2015-01-06 22:58 1622<!-- 定义Filter --> <fi ... -
JSP中out.print 和 out.write 区别
2015-01-06 22:55 1632jsp中的out对象是JspWriter类型的.而JspWri ... -
使用Eclipse开发Java Web过程中Debug调试的使用方法
2014-03-06 21:35 1584这里介绍的是在Eclipse中的Debug调试。 首先右击 ... -
iBATIS CDATA
2014-02-27 23:52 803在ibatis 中,SQL语句经常会出现一些特殊符号,比如:& ... -
isNotEmpty isNotNull
2014-01-27 14:20 1499ibatis : isNotEmpty:过滤空串"& ... -
读书:《代码整洁之道》
2014-01-17 00:10 11801. 本书内容概要 核心观 ... -
String,StringBuffer和StringBuild性能
2014-01-08 22:09 938在不考虑线程安全的前 ... -
stringbuffer 的缓冲长度
2014-01-08 22:06 13941 StringBuffer缓冲长度,或者叫容量会随着 ... -
重构——代码的坏味道
2014-01-04 00:17 842重构——代码的坏味道 1. Duplicated Code(重 ... -
xls与csv文件是什么区别?功能和作用上有什么不同
2013-11-03 22:30 196771 xls 文件就是Microsoft e ... -
toString() ,String,String.valueOf
2013-07-20 00:52 2445常用的方法有Object#toString(),(String ... -
jre与jdk的区别
2013-07-20 00:48 2545JDK就是Java Development Kit. ... -
Java编译原理
2013-01-22 21:11 1837Java编译原理 1. 关于动 ... -
JVM的基本工作原理和特点
2013-01-22 21:08 1296JVM的基本工作原理和特点 操作系统装入jvm是通过jd ... -
Math的属性之对数
2013-01-22 11:20 1526Math.LN2 2的自然对数 Math.LN10 10的自然 ... -
面试题50
2013-01-14 23:37 1366【程序1】 题目:古典问题:有一对兔子,从出生后第3个月起 ...
相关推荐
进程通信实验报告进程通信实验报告进程通信实验报告进程通信实验报告进程通信实验报告进程通信实验报告
常用的几种进程通信方式的比较常用的几种进程通信方式的比较
操作系统的第二次作业进程和进程通信,里面截图中的姓名与学号自己PS改一下吧
共享内存,进程通信,进程同步 源代码 vs2005
window进程通信方法主要介绍了在window下进程通信的常用机制
请参考本人上传课件-实验二 进程和进程通信 压缩包包含全部5个程序
操作系统实验二:进程通信机制的应用实验报告。加深对于进程并发执行概念的理解。实践并发进/线程的创 建和控制方法。观察和体验进程的动态特性。进一步理解进程生命期期间创建、变换、撤销状态变换的过程。掌握进程...
分别利用UNIX的消息通信机制、共享内存机制(用信号灯实施进程间的同步和互斥)实现两个进程间的数据通信。具体的通信数据可从一个文件读出,接收方进程可将收到的数据写入一个新文件,以便能判断数据传送的正确性。
2.4 实验四:使用命名管道实现进程通信.doc
进程线程通信,线程同步,异步,进程通信经典
LINUX进程通信实验 君若为我痴情,吾愿为君死身。
进程通信 操作系统 课程设计 进程通信 操作系统 课程设计
计算机操作系统实验-进程通信(一)
使用剪贴板实现进程通信 使用剪贴板实现进程通信 使用剪贴板实现进程通信 使用剪贴板实现进程通信
使用匿名管道实现进程通信 使用匿名管道实现进程通信 使用匿名管道实现进程通信
qt使用QProcess实现父子进程通信
自定义消息实现进程通信 使用MFC模拟实现进程间的通信,一个发送程序,一个接受程序,两个进程实现。
android多进程通信
本人写了一个java进程通信的工具jar,方便大家简单的使用java进程通信。 开启守护进程,获取消息: package com.test; import org.msun.process.ProcessMonitor; import org.msun.process.ProcessMonitor....
windows API 进程通信-生产者消费者问题,利用共享内存的方法实现