【问题标题】:Multple writer single reader synchronization in multiple process environment?多进程环境中的多写单读同步?
【发布时间】:2013-11-12 05:58:36
【问题描述】:

我有一个项目,其中多个写入器(使用多线程)使用一个进程写入,而单个读取器(单线程)通过另一个进程读取此写入。作家和读者一直在做同样的事情。 Writer 在每次写入时都会写入可变数据行,因此我无法使用缓冲区。我想使用内存映射文件或我可以在其中编写此文件的单个文件。

我对同步感到困惑。由于我在 2 个过程中执行此操作,因此不能使用条件变量,因此只需要使用信号量。

现在,如果我使用信号量,那么几个写入器同时写入,因此它会覆盖另一个写入器之前写入的数据,当读取器读取时,它将只读取最新写入,我将丢失所有以前的写入。我希望读取器应该读取发生的每一次写入.有些延迟是可以接受的。

我也可以尝试将一件事全部写入一个文件,然后让线程休眠一段时间,然后在休眠期间读取它们,但这样做我可能会丢失一些可能在休眠期间到达的数据。

知道如何实现吗?任何帮助都很棒。我正在使用 C 和 Linux 平台。因此,请提出与 C 和 Linux/Unix 相关的建议。

更新1: 我已经为信号量完成了以下步骤:

                       semget(key,2,flag)  //define 2 semaphore
         semctl(semid,0,SETVAL,0)  //Initialize value for semaphore 0
         semctl(semid,1,SETVAL,0)  //Initialize value for semaphore 0

         writer_lock(semid)  //writer lock
              struct sembuf action[2] ;
            action[0].sem_num = 0;
            action[0].sem_flg = SEM_UNDO;
            action[0].sem_op  = 0 ;
            action[1].sem_num = 1;
            action[1].sem_flg = SEM_UNDO;
            action[1].sem_op  = +1 ;
              semop(sem_id,action,2);

          release_writer_lock
              struct sembuf action[1] ;
            action[0].sem_num = 1;
            action[0].sem_flg = SEM_UNDO;
            action[0].sem_op  = -1 ;
             semop(sem_id,action,1);

         reader_lock(semid)
               struct sembuf action[2] ;
            action[0].sem_num = 1;
            action[0].sem_flg = SEM_UNDO;
            action[0].sem_op  = 0 ;
            action[1].sem_num = 0;
            action[1].sem_flg = SEM_UNDO;
            action[1].sem_op  = +1 ;
             semop(sem_id,action,2) 


          release_reader_lock
              struct sembuf action[1] ;
            action[0].sem_num = 0;
            action[0].sem_flg = SEM_UNDO;
            action[0].sem_op  = -1 ;
             semop(sem_id,action,1);

        ** writer end***
        writer_lock(semid)
          /* my work*/
        release_writer_lock(semid)


        ** reader end***
        reader_lock(semid)
          /* read and clear */
        release_reader_lock(semid)

【问题讨论】:

    标签: c linux multithreading synchronization


    【解决方案1】:

    您需要使用一对信号量 - 一个信号量阻止读取器,直到写入器创建要读取的内容,另一个阻止写入器,直到读取器读取现有消息。

    将读取信号量初始化为 0,将写入信号量初始化为 1。读取器执行以下操作:

    sem_wait(&read_sem);
    /* Read and remove message */
    sem_post(&write_sem);
    

    作者是这样的:

    sem_wait(&write_sem);
    /* Write message */
    sem_post(&read_sem);
    

    【讨论】:

    • 我在帖子中做了一些更改,您能否建议我使用它而不是使用 sem_wait 和 sem_post。另外请建议我是否使用普通文件并打开几个会话进行写作会不会有问题?还是我应该使用内存映射文件?
    • 您的代码使用旧式 SysV 信号量,我建议改用 POSIX 信号量(sem_init()sem_wait()sem_post())。
    • 您的 -1+1 值也有误——“锁定”操作应该减一,而“解锁”操作应该加一。 release_writer_lockrelease_reader_lock 操作错误的信号量。
    • 知道了。感谢指点错误。我会更正它并尝试使用 POSIX std 来实现,尽管我不知道如何使用它。会检查一些教程。
    • @TusharGoel:如果需要,您可以使用 SysV 信号 - 请注意,+1sem_op 对应于 sem_post()-1sem_op 对应于sem_wait().
    【解决方案2】:

    注意:
    1。如果读取器进程正在读取,则写入器进程不应写入。
    2。如果任何写入器线程正在写入,则读取器进程无法读取,因为源文件(如您所述)正忙。

    因此,应该只有一个同步变量(比如 sem_id)应该由读取器进程和写入器进程使用。此外,所有编写器线程都应使用此变量以避免覆盖。

    编写器进程

     writer_thread1 
      {
       writer_lock(sem_id);
         write the data
       release_writer_lock(sem_id);
      }
     writer_thread2 
      {
       writer_lock(sem_id);
         write the data
       release_writer_lock(sem_id);
      }
    

    阅读器进程

      reader 
      {
       reader_lock(sem_id);
         read the data
       release_reader_lock(sem_id);
      }
    

    编辑
    很抱歉忽略了消息槽限制。但是我建议这个解决方案认为您正在使用共享文件(您正在写入和读取),正如您在问题中提到的那样。此外,您的问题提到它有几个编写器线程,但很明显它不可能同时写入共享位置。
    如果只有一个消息槽,则只能按照@caf 所述进行。但是,我认为使用多个写入线程是没有用的,因为任何写入线程只有在读取进程读取数据时才能写入数据。

    【讨论】:

    • 这个方案的问题是后续的写入者会覆盖之前的未读消息——OP暗示只有一个消息槽可用,后续的写入者应该等到之前写入的消息被读取.
    • @caf 我正在实施相同的方法。根据您的说法,它将无法正常工作。需要使用 POSIX 方式,但有什么方法可以纠正这个问题?
    • @caf 抱歉,我忽略了这一点。现已编辑。由于您的解决方案使用两个信号量,因此在我看来,写入器线程只能在读取器进程读取前一个信号量时写入。因此,尽管有多个写入器,但我们不能使用它们,因为只有读取器进程具有每个写入器线程正在等待的 sem_post(&read_sem)
    • @RaviKant:是的,但并不一定意味着拥有多个作家没有意义。也许编写者正在执行一些长时间运行、资源密集型的任务,并将结果传递给单个读取器,读取器处理结果的速度比编写器生成结果的速度要快得多。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-11-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-07-29
    • 2012-10-10
    • 1970-01-01
    相关资源
    最近更新 更多