/Lib/test/test_thread.py

http://unladen-swallow.googlecode.com/ · Python · 168 lines · 127 code · 32 blank · 9 comment · 25 complexity · 85425d42f9b91ae6c9cd747663ccb02f MD5 · raw file

  1. import os
  2. import unittest
  3. import random
  4. from test import test_support
  5. import thread
  6. import time
  7. NUMTASKS = 10
  8. NUMTRIPS = 3
  9. _print_mutex = thread.allocate_lock()
  10. def verbose_print(arg):
  11. """Helper function for printing out debugging output."""
  12. if test_support.verbose:
  13. with _print_mutex:
  14. print arg
  15. class BasicThreadTest(unittest.TestCase):
  16. def setUp(self):
  17. self.done_mutex = thread.allocate_lock()
  18. self.done_mutex.acquire()
  19. self.running_mutex = thread.allocate_lock()
  20. self.random_mutex = thread.allocate_lock()
  21. self.running = 0
  22. self.next_ident = 0
  23. class ThreadRunningTests(BasicThreadTest):
  24. def newtask(self):
  25. with self.running_mutex:
  26. self.next_ident += 1
  27. verbose_print("creating task %s" % self.next_ident)
  28. thread.start_new_thread(self.task, (self.next_ident,))
  29. self.running += 1
  30. def task(self, ident):
  31. with self.random_mutex:
  32. delay = random.random() / 10000.0
  33. verbose_print("task %s will run for %sus" % (ident, round(delay*1e6)))
  34. time.sleep(delay)
  35. verbose_print("task %s done" % ident)
  36. with self.running_mutex:
  37. self.running -= 1
  38. if self.running == 0:
  39. self.done_mutex.release()
  40. def test_starting_threads(self):
  41. # Basic test for thread creation.
  42. for i in range(NUMTASKS):
  43. self.newtask()
  44. verbose_print("waiting for tasks to complete...")
  45. self.done_mutex.acquire()
  46. verbose_print("all tasks done")
  47. def test_stack_size(self):
  48. # Various stack size tests.
  49. self.assertEquals(thread.stack_size(), 0, "intial stack size is not 0")
  50. thread.stack_size(0)
  51. self.assertEquals(thread.stack_size(), 0, "stack_size not reset to default")
  52. if os.name not in ("nt", "os2", "posix"):
  53. return
  54. tss_supported = True
  55. try:
  56. thread.stack_size(4096)
  57. except ValueError:
  58. verbose_print("caught expected ValueError setting "
  59. "stack_size(4096)")
  60. except thread.error:
  61. tss_supported = False
  62. verbose_print("platform does not support changing thread stack "
  63. "size")
  64. if tss_supported:
  65. fail_msg = "stack_size(%d) failed - should succeed"
  66. for tss in (262144, 0x100000, 0):
  67. thread.stack_size(tss)
  68. self.assertEquals(thread.stack_size(), tss, fail_msg % tss)
  69. verbose_print("successfully set stack_size(%d)" % tss)
  70. for tss in (262144, 0x100000):
  71. verbose_print("trying stack_size = (%d)" % tss)
  72. self.next_ident = 0
  73. for i in range(NUMTASKS):
  74. self.newtask()
  75. verbose_print("waiting for all tasks to complete")
  76. self.done_mutex.acquire()
  77. verbose_print("all tasks done")
  78. thread.stack_size(0)
  79. class Barrier:
  80. def __init__(self, num_threads):
  81. self.num_threads = num_threads
  82. self.waiting = 0
  83. self.checkin_mutex = thread.allocate_lock()
  84. self.checkout_mutex = thread.allocate_lock()
  85. self.checkout_mutex.acquire()
  86. def enter(self):
  87. self.checkin_mutex.acquire()
  88. self.waiting = self.waiting + 1
  89. if self.waiting == self.num_threads:
  90. self.waiting = self.num_threads - 1
  91. self.checkout_mutex.release()
  92. return
  93. self.checkin_mutex.release()
  94. self.checkout_mutex.acquire()
  95. self.waiting = self.waiting - 1
  96. if self.waiting == 0:
  97. self.checkin_mutex.release()
  98. return
  99. self.checkout_mutex.release()
  100. class BarrierTest(BasicThreadTest):
  101. def test_barrier(self):
  102. self.bar = Barrier(NUMTASKS)
  103. self.running = NUMTASKS
  104. for i in range(NUMTASKS):
  105. thread.start_new_thread(self.task2, (i,))
  106. verbose_print("waiting for tasks to end")
  107. self.done_mutex.acquire()
  108. verbose_print("tasks done")
  109. def task2(self, ident):
  110. for i in range(NUMTRIPS):
  111. if ident == 0:
  112. # give it a good chance to enter the next
  113. # barrier before the others are all out
  114. # of the current one
  115. delay = 0
  116. else:
  117. with self.random_mutex:
  118. delay = random.random() / 10000.0
  119. verbose_print("task %s will run for %sus" %
  120. (ident, round(delay * 1e6)))
  121. time.sleep(delay)
  122. verbose_print("task %s entering %s" % (ident, i))
  123. self.bar.enter()
  124. verbose_print("task %s leaving barrier" % ident)
  125. with self.running_mutex:
  126. self.running -= 1
  127. # Must release mutex before releasing done, else the main thread can
  128. # exit and set mutex to None as part of global teardown; then
  129. # mutex.release() raises AttributeError.
  130. finished = self.running == 0
  131. if finished:
  132. self.done_mutex.release()
  133. def test_main():
  134. test_support.run_unittest(ThreadRunningTests, BarrierTest)
  135. if __name__ == "__main__":
  136. test_main()