code: def test_max_tasks_per_child(self):
      context = self.get_context()
      if context.get_start_method(allow_none=False) == "fork":
          with self.assertRaises(ValueError):
              self.executor_type(
                  1, mp_context=context, max_tasks_per_child=3
              )
          return
      # not using self.executor as we need to control construction.
      # arguably this could go in another class w/o that mixin.
      executor = self.executor_type(
          1, mp_context=context, max_tasks_per_child=3
      )
      f1 = executor.submit(os.getpid)
      original_pid = f1.result()
      # The worker pid remains the same as the worker could be reused
      f2 = executor.submit(os.getpid)
      self.assertEqual(f2.result(), original_pid)
      self.assertEqual(len(executor._processes), 1)
      f3 = executor.submit(os.getpid)
      self.assertEqual(f3.result(), original_pid)
  
      # A new worker is spawned, with a statistically different pid,
      # while the previous was reaped.
      f4 = executor.submit(os.getpid)
      new_pid = f4.result()
      self.assertNotEqual(original_pid, new_pid)
      self.assertEqual(len(executor._processes), 1)
  
      executor.shutdown()
  
imports: import os
  import sys
  import threading
  import time
  import unittest
  from concurrent import futures
  from concurrent.futures.process import BrokenProcessPool
  from test import support
  from test.support import hashlib_helper
  from .executor import ExecutorTest, mul
  from .util import ProcessPoolForkMixin, ProcessPoolForkserverMixin, ProcessPoolSpawnMixin, create_executor_tests, setup_module
label_desc: Use image node_id 10 for calling the ProcessPoolExecutorTest obj's underlying member method code with example usage: obj.test_max_tasks_per_child() without return types