0

这是我正在尝试做的事情:

  1. 从主线程启动 10 个 posix 线程。
  2. 10 个线程中的每一个都会执行一些操作,比如 100 次。

这是我需要帮助的。

  1. 我想允许 thread_1 做它的事情 10 秒(同时线程 2-10 被挂起),然后我想允许线程 2 在线程 1 和线程 3-10 被挂起时做它的事情,依此类推。

我该怎么做?我在看一些 pthread 教程,但事情似乎很复杂,尽管我想做的事情很简单。

4

3 回答 3

3

除了关于 OP 的问题是否有意义的任何讨论之外,可能的解决方案可能如下:

为每个要调度的线程安装一个信号处理程序。这个处理程序在 say 上被触发,SIGUSR1并且在内部除了调用对pause().

线程函数都以调用 开始pause(),它在创建后立即挂起所有线程。

使用 .创建所有要调度的线程pthread_create()。将创建的 pthread 存储到一个数组pthreads中。

将要运行的第一个 pthread(从pthread)分配给pthread_first.

开始调度调用pthread_kill(pthread_first, SIGUSR2)以恢复首先运行的线程(通过pause()使其阻塞返回)。使pthread_current成为pthread_first.

为了实际执行调度,一个附加线程(可能是主线程)无限循环并调用sleep(SCHEDULING_INTERVALL),然后调用pthread_kill(pthread_current, SIGUSR1)以挂起当前线程(通过调用其信号处理程序并运行到pause())。然后调用pthread_kill(pthread_next, SIGUSR2)以恢复下一个线程(通过pause()使其阻塞返回)。Make pthreat_currentbecome pthread_next,并成为线程创建期间填充pthread_next的数组中的另一个条目。pthread

但请注意:

由于被信号中断并被挂起的线程pause()可能在共享资源上做一些工作的过程中被捕获并保持它们直到恢复,相互踩到对方脚趾的机会非常高。

对所有其他人:是的,打败我;-)


更新:

等效示例:

#include <errno.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <pthread.h>
#include <signal.h>

#define THREADSMAX (3)
#define SCHEDULING_INTERVALL (5) /* seconds */

void
sigusr_handler(int signo)
{
  if (SIGUSR1 == signo)
    {
      pause();
    }
}

void *
thread_function(void * pv)
{
  intptr_t iThread = (intptr_t) pv;

  pause();

    {
      int i = 0;
      for (;;)
        {
          printf("%d: %d\n", (int) iThread, i++);
          sleep(1);
        }
    }

  pthread_exit(NULL);
}

int
main(int argc, char ** argv)
{
  struct sigaction signal_action;
  memset(&signal_action, 0, sizeof(signal_action));
  signal_action.sa_handler = sigusr_handler;
  sigemptyset(&signal_action.sa_mask);

  sigaction(SIGUSR1, &signal_action, NULL);
  sigaction(SIGUSR2, &signal_action, NULL);

    {
      pthread_t threads[THREADSMAX] =
        { 0 };

      intptr_t iThread = 0;

      /* create threads */
      for (; iThread < THREADSMAX; ++iThread)
        {
          int iResult = pthread_create(&threads[iThread], NULL, thread_function,
              (void *) iThread);
          if (iResult)
            {
              errno = iResult;
              perror("pthread_created()");
              exit(1);
            }
        }

      sleep(1); /* Unreliable workaround: Try to make sure all threads have started and block in "pause()". See comments on how this might be fixed nicely ... */

      /* scheduling loop */
      for (iThread = 0;; ++iThread)
        {
          if (THREADSMAX == iThread)
            {
              iThread = 0;
            }
            /* Resume current thread */
            {
              int iResult = pthread_kill(threads[iThread], SIGUSR2);
              if (iResult)
                {
                  errno = iResult;
                  perror("pthread_kill(..., SIGUSR2)");
                  exit(2);
                }
            }

          sleep(SCHEDULING_INTERVALL);

          /* Suspend current thread */
            {
              int iResult = pthread_kill(threads[iThread], SIGUSR1);
              if (iResult)
                {
                  errno = iResult;
                  perror("pthread_kill(..., SIGUSR1)");
                  exit(3);
                }
            }
        }
    }

  return 0;
}

预期输出:

0: 0
0: 1
0: 2
0: 3
0: 4
1: 0
1: 1
1: 2
1: 3
1: 4
2: 0
2: 1
2: 2
2: 3
2: 4
0: 5
0: 6
0: 7
0: 8
0: 9
1: 5
1: 6
1: 7
1: 8
1: 9
2: 5
2: 6
...
于 2013-05-04T11:08:15.063 回答
1
  1. POSIX 线程:条件变量 - 有什么意义?
  2. 加入和分离线程在此处输入图像描述
  3. 使用sleep()和调度程序将上下文切换到另一个进程。IMO 它不是那么糟糕的解决方案 - 它不是通用的,因为在某些情况下 100 毫秒是很多时间,而在另一种情况下它非常短。
  4. 由我们自己实现条件变量或某种同步器- 但确实不建议这样做。
于 2013-05-03T23:40:41.217 回答
1

您没有很好地说明您的要求。线程是否都对独立数据进行操作(它们之间不需要同步)?如果是这样,尝试以 10 秒为单位进行自己的课程安排的整个想法是荒谬的。让他们都跑,做他们的事。当然,使用计时器信号并控制哪些线程阻塞了信号会很容易实现您的要求,但它也完全没用。

另一方面,如果您的线程之间确实存在数据依赖关系,那么“运行 10 秒然后将控制权转移到另一个线程”的任何模式都是无效的;如果下一个线程由于第一个线程持有的锁而无法继续进行,则可能导致死锁。(我想它并不完全是死锁,因为控制最终会返回到第一个线程,但是如果涉及多个锁,延迟可能会以非常大的顺序增长。)相反,在这种情况下,您应该瞄准线程运行受数据流控制。

于 2013-05-04T02:39:54.600 回答