This issue tracker has been migrated to GitHub, and is currently read-only.
For more information, see the GitHub FAQs in the Python's Developer Guide.

classification
Title: threading issue in __builtins__.print
Type: behavior Stage:
Components: IO Versions: Python 3.1
process
Status: closed Resolution: fixed
Dependencies: Superseder:
Assigned To: pitrou Nosy List: amaury.forgeotdarc, nullnil, pitrou
Priority: normal Keywords: needs review, patch

Created on 2009-08-21 07:28 by nullnil, last changed 2022-04-11 14:56 by admin. This issue is now closed.

Files
File name Uploaded Description Edit
textiowrapper_write.patch amaury.forgeotdarc, 2009-08-21 12:34
Messages (4)
msg91807 - (view) Author: Jackson Yang (nullnil) Date: 2009-08-21 07:28
# Bug Description
In a multi-threaded environment, the Win32 Python3000 built-in function
"print" may give the output several times.

# How to Reproduce:
import threading
event = threading.Event()
class Test(threading.Thread):
    def __init__(self, ord):
        super().__init__()
        self.ord = ord
    def run(self):
        event.wait()
        print('Hello, world!', self.ord)
threads = tuple(map(Test, range(8)))
tuple(map(lambda thread: thread.start(), threads))
event.set()
tuple(map(lambda thread: thread.join(), threads))
# EOF

# Problem Observed
[The first run, 0 is doubled]
Hello, world! 0
Hello, world! 0
Hello, world! 1
Hello, world! 2
Hello, world! 3
Hello, world! 4
Hello, world! 5
Hello, world! 6
Hello, world! 7

[the second run, 1 and 7 are doubled]
Hello, world! 1
Hello, world! 1
Hello, world! 2
Hello, world! 3
Hello, world! 4
Hello, world! 5
Hello, world! 6
Hello, world! 7
Hello, world! 7
Hello, world! 0

# Expected Result
Each thread gives ONE AND ONLY ONE output.
OR
State this as The Expected Behavior, document it and ask the user to
write something such as critical section.
msg91823 - (view) Author: Amaury Forgeot d'Arc (amaury.forgeotdarc) * (Python committer) Date: 2009-08-21 12:34
The TextIOWrapper class is not thread-safe, because it calls [the
equivalent of] self.buffer.write(self.pending_bytes) before clearing
self.pending_bytes.
Of course the write() function will release the GIL, and another thread
may send the same pending_bytes again.

Patch is attached. Antoine, can you review it?

(_pyio.TextIOWrapper does no buffering.)
msg92061 - (view) Author: Antoine Pitrou (pitrou) * (Python committer) Date: 2009-08-29 11:22
The patch looks ok to me.
It should be noted that TextIOWrapper was not designed to be thread-safe
at all (neither the Python nor the C version); but admittedly it is more
common to write() than to read() from multiple threads, so fixing this
particular case makes sense.
msg92073 - (view) Author: Amaury Forgeot d'Arc (amaury.forgeotdarc) * (Python committer) Date: 2009-08-29 23:26
fixed with r74581, r74582 and r74583 (in: trunk, py3k and release31-maint)
History
Date User Action Args
2022-04-11 14:56:52adminsetgithub: 50999
2009-08-29 23:26:08amaury.forgeotdarcsetstatus: open -> closed
resolution: fixed
messages: + msg92073
2009-08-29 11:22:13pitrousetmessages: + msg92061
2009-08-21 12:34:58amaury.forgeotdarcsetfiles: + textiowrapper_write.patch

nosy: + amaury.forgeotdarc, pitrou
messages: + msg91823

assignee: pitrou
keywords: + needs review, patch
2009-08-21 07:28:27nullnilcreate