【问题标题】:Multiple Processes and Threads synchronization and ordering in CC中的多进程和线程同步和排序
【发布时间】:2014-08-16 14:55:36
【问题描述】:

我想要完成的是在每个处理匿名映射共享内存的新进程中创建 3 个进程和一个新线程。我还是多线程和 IPC 的新手,所以也许我没有正确使用它们,但我已经尝试过互斥锁、信号量和条件变量,当我接近在它们之间传递内存时,它要么挂起,要么似乎没有完全传递信息。

我想做的是:

  1. 第一个 fork() 的进程创建一个线程并从文件中读取。
  2. 第二个进程创建一个新线程来处理共享内存以改变它。
  3. 第三个进程创建线程以再次更改共享内存,然后将其输出到文件。

我知道我可以通过管道和仅 3 个进程来完成此任务,但我想尝试共享内存和线程。

是否有可能以这样的方式对流程进行排序

  • 第一个进程->第一个线程->第二个进程->第二个线程->第三个进程->第三个线程

会这样运行吗?对于 N 个进程和 N 个线程,有什么方法可以做到这一点吗?我觉得我应该可以,但我对此还不够熟悉。感谢您的任何想法和建议,提前致谢。

编辑:我在调用 fork() 中找到了解决方案,但在进程中重新排序了被调用的线程。查看下面的示例。

更新的问题:我发现当 memcpy()'ing 在某个线程中时,我可以为一个缓冲区更新共享内存中的一个缓冲区,但不能为另一个缓冲区更新。在下一个线程中,我的一个缓冲区已满,但另一个缓冲区未满,即使快速检查显示在离开线程之前两个缓冲区中都有数据?我遇到了什么样的并发错误?感谢您的想法和建议,在此先感谢。

【问题讨论】:

    标签: c multithreading process pthreads ipc


    【解决方案1】:

    感谢@MichaelGoren 和一些细微的修改,我找到了一个解决方案。我基本上重新排序了按进程顺序调用的线程。我没有使用信号量,而是让我的父线程等待他们的子线程完成。所以,

    1. 我为我的第一个进程调用了 fork(),并告诉父进程等待它的子进程。我在这个和下一个 fork() 之间也有一个管道。我在这个父级中调用了我的第三个线程。
    2. 我调用了我的下一个进程并让它等待它的子进程并将我的第二个线程放入其中。这个孩子现在将成为它自己的父调用者,在这个和最后一个孩子之间有另一个管道。
    3. 我在最后一个孩子中调用了我的第一个线程。

    如前所述,我还使用了一些共享内存。

    按照顺序,第二个孩子 -> 第一个线程 -> 第一个孩子 -> 第二个线程 -> 父级 -> 第三个线程。

    现在,我不确定这是否是万无一失的,所以如果这可能不是并发的,请随时纠正我。

    【讨论】:

      【解决方案2】:

      这个问题相当笼统,广泛而深入。 因此,我的回答将使您初步了解多线程/多处理。 首先,我将问题分为两个主要问题: 1)单个进程内的线程同步。 2)单线程进程同步。 稍后您可以将 (1) 和 (2) 结合起来,不要忘记混合线程和分叉导致的特殊问题和副作用。

      1。线程同步。

      假设我们有一个具有 3 个(或 M,在一般情况下)线程 t1、t2 和 t3 的进程,它们应该以强顺序运行:t1、t2 和 t3。即使您完全按照这个顺序创建这些线程,也没有人能保证它们会按照这个顺序启动。您可以通过强制它们等待两个条件变量:c1 和 c2 来阻止 t2 和 t3 的执行。当 t1 和 t2 线程准备好时,上述条件变量将向 t2 和 t3 线程发出信号。 t1 线程将“解除阻塞”c1 变量,t2 线程将“解除阻塞”c2。 因此,您所需要的只是与两个(或 M-1)互斥锁关联的两个(或 M-1)条件变量和负责线程状态的两个(或 M-1)布尔值。这是一个简化的代码。虽然它可以工作(您可以使用 gcc -lpthread 编译它),但您的“真实”代码应该将变量组织成结构,检查错误等。

      #include <pthread.h>
      #include <stdio.h>
      
      // These are mentioned mutexes, conditional variables and booleans.
      // They are global, so any thread can access them.
      pthread_mutex_t m1 = PTHREAD_MUTEX_INITIALIZER;
      pthread_cond_t  c1 = PTHREAD_COND_INITIALIZER;
      int t1_is_ready = 0;
      
      pthread_mutex_t m2 = PTHREAD_MUTEX_INITIALIZER;
      pthread_cond_t  c2 = PTHREAD_COND_INITIALIZER;
      int t2_is_ready = 0;
      
      // This function is invoked by the t1 thread.
      // It does not depend on conditional variables and always is executed first.
      // When it's ready it sets its ready status to one and signal to the thread t2
      // via c2, that the status has changed.
      void* t1_work(void* arg)
      {
        pthread_mutex_lock(&m1);
        printf("thread t1 does its work\n");
        t1_is_ready = 1;
        pthread_mutex_unlock(&m1);
        pthread_cond_signal(&c1);
      
        pthread_exit(NULL);
      } 
      
      // This function is invoked by the t2 thread.
      // It is blocked until t1 setis is ready status to 1.
      // Pay your attention how to wait on a conditional variable:
      // with locked mutex and in a loop, to prevent spurious wakes up. 
      void* t2_work(void* arg)
      {
        pthread_mutex_lock(&m1);
        while(t1_is_ready == 0)
        {
          pthread_cond_wait(&c1, &m1);
        }
        pthread_mutex_unlock(&m1);
      
        pthread_mutex_lock(&m2);
        printf("thread t2 does its work\n");
        t2_is_ready = 1;
        pthread_mutex_unlock(&m2);
        pthread_cond_signal(&c2);
      
        pthread_exit(NULL);
      }
      
      // This function is invoked by the t3 thread.
      void* t3_work(void* arg)
      {
        pthread_mutex_lock(&m2);
        while(t2_is_ready == 0)
        {
          pthread_cond_wait(&c2, &m2);
        }
      
        printf("thread t3 does its work\n");
        pthread_mutex_unlock(&m2);
      
        pthread_exit(NULL);
      }
      
      int main(void)
      {
        pthread_t t1;
        pthread_t t2;
        pthread_t t3;
      
        pthread_create(&t1, NULL, t1_work, NULL);
        pthread_create(&t2, NULL, t2_work, NULL);
        pthread_create(&t3, NULL, t3_work, NULL);
      
        pthread_join(t1, NULL);
        pthread_join(t2, NULL);
        pthread_join(t3, NULL);
      
        return 0;
      }
      

      2。进程同步

      这是一篇不错的文章,其中包含进程同步的代码示例: http://www.linuxdevcenter.com/pub/a/linux/2007/05/24/semaphores-in-linux.html?page=5 由于您计划通过 fork() 函数创建流程,因此它们将被称为“相关”。如果您有 3(或 N)个正在运行的进程创建 2(N-1)个信号量,以您同步线程的方式使用它们。

      【讨论】:

      • 您好,我目前正在修改我的程序,除了一些小问题外,它几乎似乎在那里。我可以将此代码发送给您以供您查看吗?我想在这里发帖可能太长了。谢谢。
      • @sdc30 很抱歉,我无法查看您的整个代码。尝试从中提取和发布重要部分,并提出更具体的问题。我(或其他参与者)很乐意回答。
      • 谢谢,我实际上找到了解决问题的方法,尽管不是我最初想要的。我把它贴在上面。
      猜你喜欢
      • 2011-06-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-12-17
      • 2013-06-04
      • 2022-01-04
      相关资源
      最近更新 更多