]> granicus.if.org Git - python/commitdiff
Raise a RuntimeError when tee iterator is consumed from different threads (GH-15567)
authorHongWeipeng <961365124@qq.com>
Thu, 29 Aug 2019 03:39:25 +0000 (11:39 +0800)
committerRaymond Hettinger <rhettinger@users.noreply.github.com>
Thu, 29 Aug 2019 03:39:25 +0000 (20:39 -0700)
Doc/library/itertools.rst
Misc/NEWS.d/next/Library/2019-08-29-10-26-57.bpo-34410.ttCIpm.rst [new file with mode: 0644]
Modules/itertoolsmodule.c

index a3f403a5b40b9cee977c30a18cc3efeb01d9e328..8e7899e6b6139af3ee42a2ec83d8be9fc2890fec 100644 (file)
@@ -643,7 +643,8 @@ loops that truncate the stream.
 
    Once :func:`tee` has made a split, the original *iterable* should not be
    used anywhere else; otherwise, the *iterable* could get advanced without
-   the tee objects being informed.
+   the tee objects being informed. the :func:`tee` iterator can not be consumed
+   from different threads, even if an underlying iterator is thread-safe.
 
    This itertool may require significant auxiliary storage (depending on how
    much temporary data needs to be stored). In general, if one iterator uses
diff --git a/Misc/NEWS.d/next/Library/2019-08-29-10-26-57.bpo-34410.ttCIpm.rst b/Misc/NEWS.d/next/Library/2019-08-29-10-26-57.bpo-34410.ttCIpm.rst
new file mode 100644 (file)
index 0000000..caddada
--- /dev/null
@@ -0,0 +1,2 @@
+Raise a RuntimeError when itertools.tee() iterator is consumed from different
+threads. Patch by hongweipeng.
index 781d0cca54196dac8e7455b0dc4867ef8216e1c5..101addcfd3a9c93e562289b5076e6a0c750123f8 100644 (file)
@@ -452,6 +452,7 @@ typedef struct {
     teedataobject *dataobj;
     int index;                  /* 0 <= index <= LINKCELLS */
     PyObject *weakreflist;
+    unsigned long thread_id;
 } teeobject;
 
 static PyTypeObject teedataobject_type;
@@ -680,6 +681,11 @@ tee_next(teeobject *to)
 {
     PyObject *value, *link;
 
+    if (to->thread_id != PyThread_get_thread_ident()) {
+        PyErr_SetString(PyExc_RuntimeError,
+            "tee() iterator can not be consumed from different threads.");
+        return NULL;
+    }
     if (to->index >= LINKCELLS) {
         link = teedataobject_jumplink(to->dataobj);
         if (link == NULL)
@@ -713,6 +719,7 @@ tee_copy(teeobject *to, PyObject *Py_UNUSED(ignored))
     newto->dataobj = to->dataobj;
     newto->index = to->index;
     newto->weakreflist = NULL;
+    newto->thread_id = to->thread_id;
     PyObject_GC_Track(newto);
     return (PyObject *)newto;
 }
@@ -745,6 +752,7 @@ tee_fromiterable(PyObject *iterable)
 
     to->index = 0;
     to->weakreflist = NULL;
+    to->thread_id = PyThread_get_thread_ident();
     PyObject_GC_Track(to);
 done:
     Py_XDECREF(it);