【问题标题】:Named semaphores instead of mutex - readers writers problem without multithreading命名信号量而不是互斥量 - 没有多线程的读者作者问题
【发布时间】:2020-06-06 23:35:11
【问题描述】:

我的目标是解决 Readers Writers[1] 问题,但仅使用孤立的进程。一个进程是写者的读者,我应该使用命名信号量,以便可以随时启动后续的读者和作者 - 而且我不能使用共享内存 - 纯同步。

更多信息: 提供 2 个实现阅读器的程序的实现,以及 编写器,以便可以在遵守限制的同时动态启动新进程。 注意并发处理的属性:安全性和活性。 还要考虑您的程序是否没有死锁

编辑:问题分为 3 个文件 文件 1. 读者:

int main(){
    sem_t *mutex;
    sem_t *write;
    int count=0;
    mutex = sem_open("/mutex", O_CREAT, 0600, 1);
    write = sem_open("/write", O_CREAT, 0600, 1);

    do{
        sem_wait(mutex);
        count++;
        if (count==1){
            sem_wait(write);
        }
        sem_post(mutex);

        printf("Critical section in readers\n");

        sem_wait(mutex);
        count--;
        if(count==0)
            sem_post(write);
        sem_post(mutex); 


    }while(1);
}

文件 2. 编写器

int main(){

    sem_t  *write;
    write = sem_open("/write", O_CREAT, 0600, 1);

    do{
        sem_wait(write); 
        printf("Critical section in writer\n");
        sem_post(write);

    }while(1);

    return 0;
}

文件 3. 删除信号量

int main(){

    sem_unlink("/mutex");
    sem_unlink("/write");

    printf("Semaphores deleted \n");

    return 0;
}

问题:

  • 当我使用 gcc -pthread file_name.c 运行 readerwriter 时,我没有 得到任何结果,就像代码没有做任何事情一样 - 过程是 运行时,光标在闪烁,但没有任何反应。

[1]: READERS and WRITERS : 阅览室容量为 n 读者。读者来到阅览室,分配一个位置,占用一段时间,然后离开。过了一段时间,他们又来了,重复这个过程。阅览室也供作家使用。但是,只有当阅览室空置时,作者才能工作,即不能有其他读者或作者。作家在房间里呆了一会儿,然后离开,过一会儿又回来了

【问题讨论】:

  • 如果您既不能使用共享内存也不能使用线程:您可以读取/写入文件并使用 fork/exec 来拥有进程而不是线程。不确定你需要 2 个信号量。尝试仅从 2 个进程开始:1 个读取器和 1 个写入器。
  • 描述读写问题。
  • 您确定您需要编写的程序负责“动态启动[ing]新进程”吗?鉴于您正在为 reader 和 writer 编写单独的程序,我的期望是启动 reader 和 writer 将是外部操作,而不是由程序本身管理的东西。这将大大降低每个程序的复杂性,并将重点放在似乎打算成为练习主题的同步对象上。
  • 说到两个程序,您的代码似乎实现了具有两个功能的 一个 程序,而不是两个程序。
  • @JohnBollinger 您能否更具体地说明我应该在哪里分离代码以及如何将重点放在同步上?我完全是初学者,我承认我听不懂你说什么

标签: c linux concurrency fork semaphore


【解决方案1】:

我的目标是解决 Readers Writers 问题,但只使用孤立的进程。一个进程是为 reader 一个为 writer,我应该使用命名信号量,这样就可以随时启动后续的 reader 和 writer - 我也不能使用共享内存 - 纯同步。

从这个有限的描述来看,你可以通过named pipes来解决这个问题。

我不能使用共享内存

代码将全局变量 countercnt 视为在进程之间共享。它们不是,每个进程都会获得具有相同值的那些的副本,对这些变量的更改不会被其他进程看到。


使用函数sem_wait and sem_post link with linker option -pthread

【讨论】:

  • 我想坚持我的代码,因为它很简单(我是一个初学者)。你能告诉我我应该改变什么吗?
  • 成功了,谢谢!我仍然有一个问题:代码是否正确地完成了它的工作(符合标准并且工作稳定)?
  • @andrew_the_coder 我不认为代码会按照您的预期进行,请参阅我的更新。您可能想发布流程应该做什么。
  • 我更新了代码。现在我必须弄清楚如何运行它们以及如何动态创建新进程。你有什么建议吗?
【解决方案2】:

您提到您必须使用“隔离进程”,但据我所知线程不是进程。要创建一个新进程,您必须使用 fork()。

此处提到的差异 (full link with difference-table):

进程是活动程序,即正在执行的程序。 它不仅仅是程序代码,因为它包括程序计数器, 进程堆栈、寄存器、程序代码等。与此相比, 程序代码只是文本部分。

线程是一个轻量级进程,可以独立管理 调度程序。它提高了应用程序的性能使用 并行性。线程共享数据段、代码等信息 段,文件等与其对等线程,而它包含自己的 寄存器、堆栈、计数器等

简单来说 - 每个进程中可以有多个线程(“轻量级进程”)。

我认为你必须使用 fork() 来创建新的进程,因为你提到了“进程”这个词。此外,您提到您需要 2 个进程(一个用于读取器,一个用于写入器),因此您必须 fork() 两次并管理这两个进程。你可以阅读 fork() here.

编辑(信号量实现):

int initsem(key_t semkey, int initval)
{
    int status = 0, semid;
    union semun {/* should to be declared according to C standards */
        int val;
        struct semid_ds *stat;
        ushort *array;
    } ctl_arg;

    if ((semid = semget(semkey, 1, SEMPERM | IPC_CREAT | IPC_EXCL)) == -1) {
        if (errno == EEXIST)
            semid = semget(semkey, 1, 0);
    }
    else    {              /* if created */
        ctl_arg.val = initval;     /* set semaphore value to the initial value*/
        status = semctl(semid, 0, SETVAL, ctl_arg);
    }

    if (semid == -1 || status == -1) { /* failure */
        perror("initsem failed");
        return(-1);
    }
    else return semid;
}

int sem_wait(int semid)
{
    struct sembuf p_buf;
    p_buf.sem_num = 0;
    p_buf.sem_op = -1;
    p_buf.sem_flg = SEM_UNDO;

    if (semop(semid, &p_buf, 1) == -1) {
        perror("p(semid) failed");
        exit(1);
    }
    else return 0;
}

int sem_post(int semid)
{
    struct sembuf v_buf;
    v_buf.sem_num = 0;
    v_buf.sem_op = 1;
    v_buf.sem_flg = SEM_UNDO;

    if (semop(semid, &v_buf, 1) == -1) {
        perror("v(semid) failed");      exit(1);
    }
    else  return 0;
}

【讨论】:

  • 我尝试实现 fork,您能否看看我的代码并告诉我方向是否正确以及我应该更改什么 - 因为代码已损坏 :)。谢谢
  • 轻量级进程 是过时的令人困惑的语言。 thread 是表示为task 调度实体的控制流。 进程 是具有一个或多个线程的虚拟地址空间。还有一些内核线程在内核地址空间内运行,即内核是一个没有 pid 的伪进程。
  • 我没有看到任何sem_init 函数。
  • @MaximEgorushkin 这是书中的术语。当然你是对的,但对于学生或初学者来说,你的答案就像中文。
  • @benjamin 我会说轻量级进程是模糊的和中文的,而线程和虚拟地址空间是具体的、精确的和有洞察力的。在那张图片中,进程是线程共享的状态——地址空间、文件描述符、信号等。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-07-13
  • 2019-10-13
  • 1970-01-01
  • 2017-08-24
相关资源
最近更新 更多