免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 1929 | 回复: 0
打印 上一主题 下一主题

消息队列的好处 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2010-01-08 10:39 |只看该作者 |倒序浏览
最近一个在mmo游戏的服务器,上面用到了消息队列。

觉得unix/linux下面的消息队列还是挺好的,可以支持多进程对一个同一个队列同时读写,因为对于消息队列
内核层已经为我们解决了同步问题,在用户层不需要额外的同步代码,直接使用就可以了。

下面贴一段代码是关于发送消息的msgsnd是实现:
关于代码的帖子:
http://topic.csdn.net/u/20090415/18/a8751048-19c4-4da3-b41d-46897cc5f2c7.html
// 先看msgsnd()函数,它通过系统调用接口界面,进入内核执行,代码如下:
SYSCALL_DEFINE4(msgsnd, int, msqid, struct msgbuf __user *, msgp, size_t, msgsz,
        int, msgflg)
{
    long mtype;
    if (get_user(mtype, &msgp->mtype))
        return -EFAULT;
    return do_msgsnd(msqid, mtype, msgp->mtext, msgsz, msgflg);
}
// 接下来看do_msgsnd()部分的代码,如下:
long do_msgsnd(int msqid, long mtype, void __user *mtext,
        size_t msgsz, int msgflg)
{
    struct msg_queue *msq;
    struct msg_msg *msg;
    int err;
    struct ipc_namespace *ns;
    ns = current->nsproxy->ipc_ns;
    if (msgsz > ns->msg_ctlmax || (long) msgsz  0 || msqid  0)
        return -EINVAL;
    if (mtype  1)
        return -EINVAL;
    msg = load_msg(mtext, msgsz);
    if (IS_ERR(msg))
        return PTR_ERR(msg);
    msg->m_type = mtype;
    msg->m_ts = msgsz;
    msq = msg_lock_check(ns, msqid);
    if (IS_ERR(msq)) {
        err = PTR_ERR(msq);
        goto out_free;
    }
    for (;;) {
        struct msg_sender s;
        err = -EACCES;
        if (ipcperms(&msq->q_perm, S_IWUGO))
            goto out_unlock_free;
        err = security_msg_queue_msgsnd(msq, msg, msgflg);
        if (err)
            goto out_unlock_free;
        if (msgsz + msq->q_cbytes = msq->q_qbytes &&
                1 + msq->q_qnum = msq->q_qbytes) {
            break;
        }
        /* queue full, wait: */
        if (msgflg & IPC_NOWAIT) {
            err = -EAGAIN;
            goto out_unlock_free;
        }
        ss_add(msq, &s);
        ipc_rcu_getref(msq);
        msg_unlock(msq);
        schedule();
        ipc_lock_by_ptr(&msq->q_perm);
        ipc_rcu_putref(msq);
        if (msq->q_perm.deleted) {
            err = -EIDRM;
            goto out_unlock_free;
        }
        ss_del(&s);
        if (signal_pending(current)) {
            err = -ERESTARTNOHAND;
            goto out_unlock_free;
        }
    }
    msq->q_lspid = task_tgid_vnr(current);
    msq->q_stime = get_seconds();
    if (!pipelined_send(msq, msg)) {
        /* noone is waiting for this message, enqueue it */
        list_add_tail(&msg->m_list, &msq->q_messages);
        msq->q_cbytes += msgsz;
        msq->q_qnum++;
        atomic_add(msgsz, &ns->msg_bytes);
        atomic_inc(&ns->msg_hdrs);
    }
    err = 0;
    msg = NULL;
out_unlock_free:
    msg_unlock(msq);
out_free:
    if (msg != NULL)
        free_msg(msg);
    return err;
}
// 在这段代码中,请注意临近入口位置的这个函数msg_lock_check(),我们跟进,看一下这个lock是如何check
// 的,代码如下:
static inline struct msg_queue *msg_lock_check(struct ipc_namespace *ns,
                        int id)
{
    struct kern_ipc_perm *ipcp = ipc_lock_check(&msg_ids(ns), id);
    if (IS_ERR(ipcp))
        return (struct msg_queue *)ipcp;
    return container_of(ipcp, struct msg_queue, q_perm);
}
// ipc_lock_check()是一个能够check所有IPC object同步信息的函数,它的定义如下:
struct kern_ipc_perm *ipc_lock_check(struct ipc_ids *ids, int id)
{
    struct kern_ipc_perm *out;
    out = ipc_lock(ids, id);
    if (IS_ERR(out))
        return out;
    if (ipc_checkid(out, id)) {
        ipc_unlock(out);
        return ERR_PTR(-EIDRM);
    }
    return out;
}
// 这里的ipc_lock()是至关重要的地方!通过这个函数的注释,也能明白它的作用了:
/**
* ipc_lock - Lock an ipc structure without rw_mutex held
* @ids: IPC identifier set
* @id: ipc id to look for
*
* Look for an id in the ipc ids idr and lock the associated ipc object.
*
* The ipc object is locked on exit.
*/
struct kern_ipc_perm *ipc_lock(struct ipc_ids *ids, int id)
{
    struct kern_ipc_perm *out;
    int lid = ipcid_to_idx(id);
    rcu_read_lock();
    out = idr_find(&ids->ipcs_idr, lid);
    if (out == NULL) {
        rcu_read_unlock();
        return ERR_PTR(-EINVAL);
    }
    spin_lock(&out->lock);
   
    /* ipc_rmid() may have already freed the ID while ipc_lock
     * was spinning: here verify that the structure is still valid
     */
    if (out->deleted) {
        spin_unlock(&out->lock);
        rcu_read_unlock();
        return ERR_PTR(-EINVAL);
    }
    return out;
}
对于msgrcv同理可得,都是在内核层已经加锁了。。。。。。。

本文来自ChinaUnix博客,如果查看原文请点:http://blog.chinaunix.net/u3/109128/showart_2143673.html
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP