进程间通信和同步

 
第二章 进程间通信和同步
前言:在linux/unix中支持多种进程间通信(IPC)的方式,主要包括:信号、信号量、消息队列和共享内存,管道(包括无名管道和FIFO)也是进程间通信的方式。
 
·2,2信号的捕获和处理:
#inlucde <signal.h> //参见POSIX.1中定义
相关函数:
sigaction(int signo, const struct sigaction *act, struct sigaction *oact); //设置信号处理器
struct sigaction{
       void (*sa_handler)();
       sigset_t sa_mask;
       int sa_flags;
};
(1) 信号处理器函数指针 (2)进程屏蔽的信号集合 3)信号处理器的标志(查阅手册)
 
int sigemptyset(sigset-t *set);              //信号集合清空
int sigfillset(sigset_t *set);            //设置包含所有信号的全集
int sigaddset(sigset_t *set, int signo);    //把一个信号加入信号集合
int sigdelset(sigset_t *set, int signo);     //把一个信号从集合里删除
int sigismember(const sigset_t *set, int signo);    //判断信号是否包含在给定集合中
int sigprocmask(int how, const sigset_t *set, sigset_t *oset);     //设置进程中断屏蔽码
how = [SIG_BLOCK, SIG_UNBLOCK, SIG_SETMASK], *oset对设置前屏蔽码做备份
 
使用信号处理器基本方法:
1.       编写信号处理函数handler_sigproc();
//信号处理函数执行完毕的最后,记得要清堵塞的信号
//sigaddset(&blockmask, SIGINT);     //信号处理器缺省堵塞的信号
//sigaddset(&blockmask, SIGTERM); //信号处理器处理的信号
//sigprocmask(SIG_BLOCK, &blockmask, NULL); //清堵塞信号
2.       设置信号处理器struct action act;
act.sa_handler = handler_sigproc;
sigemptyset(act.sa_mask);
sigaddset(&act.sa_mask, SIGTERM); //信号处理器执行期间堵塞相应的信号
sigaction(SIGTERM, &act, NULL);//(kill产生)终止信号加入act信号处理器
 
快系统调用、慢系统调用都可能被信号打断,POSIX.1把被中断的系统调用返回-1errno设置为EINTER,只要不是“原子操作”都可能被打断,注意对这类问题的容错处理:
ret = read(fd, buf, 255); 
if (ret == -1 && errno == EINTER) //如果 (系统调用是由中断引起的执行失败) 则……
 
·2.3 信号量
有名信号量是全局,只要知道它的名字就可以使用它;
无名信号量是局部,只能通过继承才能使用它;
 
相关函数:
头文件:<sys/types.h>, <sys/ipc.h>, <sys/sem.h>
int semget(key_t key, int nsems, int semflg);              //创建或取得一个信号量组
int semctl(int sem_id, int semnum, int cmd);     //信号量控制函数(取值/删除/设置等)
int semop(int semid, struct sembuf *sops, int nsops); //信号量操作函数
(1)    信号量组ID 2)进行怎样操作3)操作次数
struct sembuf{
       short sem_num;     //对信号量组第sem_num个进行操作
       short sem_op;        //对信号量sem_value执行 -1P操作,+1V操作
       short sem_flg;        //通常取0,如果使用SEM_UNDO退出进程后,信号量值变为0
};
使用信号量基本流程:
1. sem_id = semget(SEM_KEY,0,0); //SEM_KEY
自定义,要确保唯一性
2. if (sem_id != -1) //如果信号量组不存在
              sem_id = semget(SEM_KEY, SEM_NUM, IPC_CREAT|IPC_EXCL|0666)
        ...//创建资源为SEM_NUM个的一个信号量组,权限为0666(可读写)
else 初始化信号量组的信号量资源个数
3实现PV操作函数:
void P(int sem_num, int sem_id)//对信号量组sem_id的第sem_num个信号量操作
{
       struct sembuf sem[1];
       sem[0].sem_num=sem_num; sem[0].sem_op = -1; sem[0].sem_flg = 0;
       if (semop(sem_id, sem, 1) == -1) //... 执行一次P操作,V操作类似
}
4 semctl(sem_id, sem_index, IPC_RMID); //手动删除信号量组
//注意“信号量组”和“信号量值”的区别!
 
·2.4 消息队列
#include <sys/msg.h>
int msgget(key_t key, int msgflg)); //创建或取得消息队列的ID,和信号量组类似
int msgctl(int msqid, int cmd, struct msqid_ds *buf);
int msgsnd(int msqid, void *msgp, size_t msgsz, int msgflg));
int msgrcv(int msqid, void *msgp, size_t msgsz, long int msgtyp, int msgflg)); //接收消息
//msgtyp=0:返回第一个消息 >0:返回第一个值=msgtyp的消息 <0:返回第一个值<=-msgtyp
 
 
消息队列使用基本原理:
子进程child发送首次登记的标志FLAG(msgtyp>0)child进程号到服务器进程server注册,在server段使用msgrcv(Q_MSG_KEY, &recv_buf, sizeof(Message)-sizeof(long), FLAG, 0)接收,Message正文不包括消息头的标志。然后server端发送server进程号,接收消息标志为子进程号的Message到子进程表示接收到先前消息。
 
―――――――――――――――――――――――――――――――――――――――
Message send_msg;              //首次登记并提交本进程的ID
send_msg.m_type = FLAG;
send_msg.process_id = getpid();
send_len = sizeof(long)+sizeof(int);
ret = msgsnd(msq_key, &send_msg, send_len, 0);
Message recv_msg, reply_msg;
//接收标志为FLAG的消息
ret = msgrcv(msq_key, &recv_msg, sizeof(Message)-sizeof(long), getpid(),FLAG,0);
reply_msg.m_type = recv_msg.process_id;   //向子进程发送反馈消息
reply_msg.process_id = getpid()          //告诉子进程服务端server进程号,准备建立交互
 
 
消息队列通过消息标志(即进程号)进行通信,如果客户/服务端进程有任何一方退出,则可能会出现消息丢失。即把退出一方的进程号作为标志的消息不会被任何进程接收,因为其他的进程号和消息标志不匹配。
 

建立连接开始数据通信
回复反馈信息
发送注册信息
Server
Client
消息队列通信

·2.5 共享内存
共享内存就是多个进程共享一端物理内存空间,通过把一段物理内存地址映射不同的虚空间来实现,而消息队列是把数据从应用缓冲区到核心缓冲区往返复制。因此共享内存的通信使用效率比消息队列高,但存在复杂的同步互斥关系。
 
函数:
int shmget((key_t key, int size, int shmflg));                      //创建或取得一块共享内存
int shmctl((int shmid, int cmd, struct shmid_ds *buf));             //共享内存操作
void *shmat((int shmid, const void *shmaddr, int shmflg));       //获取共享内存的指针
int shmdt((const void *shmaddr));                                   //将共享内存块从进程中分离/删除
 
 
·小结:
消息队列可以进行多路复用,进程间同步不需要复杂的同步互斥。数据以流的方式传递,
各消息都是独立且可以区分的。信息的具体语义需要收发两端的进程自己去定义和解释。消
息队列的缺点是需要进行两次数据复制,从用户空间到核心,在从核心到用户空间。
共享内存不需要多次拷贝,在数据量大的进程间同步中,用共享内存方式可以提高效率,
但是会需要复杂的进程间同步互斥控制。

Trackback: http://tb.blog.csdn.net/TrackBack.aspx?PostId=1605384


<script src="http://localhost:82/PromoteIcon.aspx?id=1605384" type="text/javascript"></script> [ 收藏到我的网摘]   andylin发表于 2007年05月12日 01:33:50
<script type="text/javascript">function hide(){showComment();}</script>
### 回答1: Qt进程间的通信和同步是指在Qt框架下,不同进程之间进行信息交流和数据同步的过程。Qt提供了多种机制来实现进程间通信同步,包括信号槽、共享内存和套接字等。 首先,Qt的信号槽机制可以实现不同进程之间的通信。通过使用信号和槽,一个进程可以发射信号,而其他进程可以接收这个信号并执行相应的槽函数。这种机制实现了进程间的异步通信,允许不同进程之间进行消息的传递和处理。 其次,Qt还提供了共享内存机制来实现进程间的数据共享和同步。使用共享内存,不同进程可以访问相同的内存空间,从而实现数据的共享。多个进程可以通过读取和写入共享内存来交换数据,并且可以使用信号量等同步机制来确保数据的一致性和同步。 此外,Qt还支持套接字通信来实现进程间的网络通信。通过创建套接字,不同进程可以建立起网络连接,进行数据的发送和接收。这种机制可以用于不同机器之间的进程通信,具有较高的灵活性和扩展性。 总之,Qt提供了多种进程间通信同步的机制,使得不同进程之间可以进行有效的信息交流和数据共享。这些机制可以根据具体的应用场景来选择和使用,以满足进程间通信同步的需求。 ### 回答2: Qt提供了多种方式来实现进程间的通信和同步。 第一种方式是使用信号与槽机制。Qt的信号与槽机制可以实现不同线程和进程之间的通信。一个进程可以发射一个信号,而另一个进程则可以将其连接到一个槽函数来接收该信号。通过信号和槽机制,可以在进程间进行异步通信,实现数据的传递和同步。 第二种方式是使用共享内存。Qt提供了QSharedMemory类,可以用于在多个进程之间共享内存区域。通过将数据存储在共享内存中,不同进程可以访问并修改这些数据,实现进程间的通信和同步。使用共享内存可以实现高效的数据传递,但需要注意在访问共享内存时进行互斥和同步操作,以避免数据竞争和不一致性。 第三种方式是使用Qt的网络模块。Qt提供了丰富的网络类,可以用于进程间的通信。可以使用QTcpSocket和QTcpServer类实现基于TCP的进程间通信,也可以使用QUdpSocket类实现基于UDP的通信。通过网络模块,可以在不同的进程之间传递数据,并进行同步操作。 总的来说,Qt提供了多种灵活的方式来实现进程间的通信和同步。开发者可以根据实际需求来选择合适的方式,并结合Qt的其他功能来实现进程间的高效交互。 ### 回答3: Qt提供了多种进程间通信同步的机制,如信号槽、共享内存和跨进程信号槽。 首先,Qt中的信号槽机制可以用于进程间通信同步。通过信号槽机制,一个进程可以发送信号,而另一个进程可以通过连接相应的槽函数来接收这些信号。这样,不同进程间就可以进行通信和同步,实现进程间数据的传递和事件的处理。 其次,Qt还提供了共享内存的机制。共享内存是一块特殊的内存区域,可以被多个进程同时访问。Qt中的QSharedMemory类可以方便地进行共享内存的创建、读写和释放。通过共享内存,进程间可以共享数据,实现数据的共享和同步。 此外,Qt还提供了跨进程信号槽机制。通过QRemoteObject模块,可以将信号槽机制扩展到跨进程通信。在跨进程信号槽中,信号的发送和接收可以在不同的进程中,进程间可以通过信号槽机制实现事件和数据的传递。 总之,Qt提供了多种进程间通信同步的机制,开发者可以根据实际需求选择合适的方式。通过这些机制,可以实现多个进程之间的数据传递和事件处理,提高程序的并发性和灵活性。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值