我该如何使用C语言编写一个监控器?

11

我需要在C语言中进行一些进程同步操作。我想使用一个监视器,已经阅读了很多相关文章。然而,我无法找到如何在C语言中实现它的方法。我看到Java和其他类似C++的语言中有实现过,但是在C语言中找不到示例。

我查阅了K&R,里面没有示例。我浏览了Unix系统编程、通信、并发和线程等书籍,但是也找不到监视器(monitor)的实现方法。

这就是我问问题的原因。如何定义监视器?如何在代码中实现它?

/* 我正在* nix环境中编码 */

3个回答

7
我最近为一个项目做了这个,我实现的概念是让一个线程启动所有其他线程,然后使用信号量和互斥锁来控制进程间同步问题,同时处理共享内存。
监视器的概念,在监视器设计模式的上下文中,是一种基本构造,用于隐藏互斥。这个概念在 C++ Boost 中有表达,但在核心 C++ 或 C 中不存在。你可以通过好老式的互斥锁(二进制信号量)和信号量来处理这种工作。你可以在这里阅读更多信息。
下面是初始化信号量和互斥锁的基本方法,你可能需要进行更多的研究,但这里是一个开始的链接。
pthread_mutex_t myMutex;
sem_t mySemaphore;
int status;
    status = pthread_mutex_init(&myMutex, NULL);
    if(status != 0)
        exit_with_error("There was an Error Initalizing the Mutex\n");
    status = sem_init(&mySemaphore, 0, 0);
    if(status != 0)
        printf("There was an Error Initalizing the Semaphore\n");

这个实现是通过一个函数吗?我见过一些类似的小代码,比如:monitor network{/在此处放置代码和条件/}。那是伪代码还是也有关于监视器的关键字/数据结构呢? - user427390
我已经取消了我之前的监视器功能,并用更直接的答案替换了它。如果您需要那段代码,请告诉我,我刚刚重新阅读了您的问题,并发现它并不完全是您要求的。在您上面的评论中,您提到的代码是伪代码,据我所知,在C语言中不存在这种结构。 - JonVD
谢谢,我想我会尝试通过在主函数中使用信号量实现我的功能,并尝试使用它来监视各个线程。我需要在这个主题上多读一些,因为它相当复杂。 - user427390
我同意,这非常复杂!在解决这些问题的过程中,很容易遇到头痛和seg_fault错误。我发的那个链接对我帮助很大。如果你有进一步的问题,就在帖子里提出来吧。 - JonVD

3
上面的代码用于初始化信号量和互斥锁非常好。这里是一个示例,演示如何在可能出现多线程错误的程序中使用它。
struct account{
        int balance;
        int finished;
        pthread_mutex_t mutex;
        pthread_cond_t deposit; 
};

static void init_account(struct account *act)
{
        act->balance = 0;
        act->finished = 0;
        pthread_mutex_init(&act->mutex,NULL);
        pthread_cond_init(&act->deposit,NULL);
}

static void deposit(struct account *act, int amount)
{
        pthread_mutex_lock(&act->mutex);
        fprintf(stderr, "Deposit:%d\n",amount);
        act->balance += amount;
        pthread_cond_broadcast(&act->deposit);
        pthread_mutex_unlock(&act->mutex);
}

0
这是我从操作系统书中解决“哲学家就餐”问题的方法。当进程或线程需要访问多个资源时,监视器比信号量更适合同步。该书为“操作系统:内部和设计原理,第七版,作者William Stallings”,第6.6章。
我知道这是一个非常老的问题,但我希望它能帮助到某些人 :)
monitor dining_controller {
    cond ForkReady[3];//clients queue here
    boolean fork[3]={true};//availability of each fork
  
    void get_forks(int pid) { //pid = client id number
        int left = pid;
        int right = (pid++) % 3;
        //grant left fork
        if (!fork[left]){ //if that fork isn't available
            cwait(ForkReady[left]);//queue so others can enter monitor
        }
        fork[left] = false;// make fork unavailable when you get it
        //grant right fork;
        if (!fork[right]){ // if that fork isn't available
            cwait(ForkReady[right]);//queue so others can enter monitor
        }
        fork[right] = false; // make fork unavailable when you get it
    }
    void release_forks(int pid){
        int left = pid;
        int right = (pid++) % 3;
        // release left fork
        if (empty(ForkReady[left])){ // no one is waiting for that fork
            fork[left] = true; //make fork available 
        }
        else{
            csignal(ForkReady[left]);//awaken process in queue
        }
        //release right fork
        if (empty(ForkReady[right])){ //no one is waiting for that fork
            fork[right] = true; //make fork available
        }
        else {
            csignal(ForkReady[right]);//awaken process in queue
        }
    }
}
void philosopher [k=0 to 2]{ //three philosopher clients
    while (true) {
        <think>;
        get_forks(k);//request to enter monitor
        <eat spaghetti>;
        release_forks(k);//request to enter monitor
    }
}

 

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接