Repository: microsoft/ptvsd

Issue:
Thread created event sent twice
## Environment data

- PTVSD version: Master
- OS and version: Mac
- Python version (& distribution if applicable, e.g. Anaconda): Python 3.6
- Using VS Code or Visual Studio: N/A

## Actual behavior

I'm getting a thread created event twice (for the same thread).

## Expected  behavior

Should get the event only once.

## Steps to reproduce:
I'm in the middle of writing some tests and here's what I'm getting back from PTVSD:
```
Event(seq=0, event='output', body={'category': 'telemetry', 'output': 'ptvsd', 'data': {'version': '0+untagged.666.g26fae95.dirty'}})
Response(seq=1, request_seq=1000, command='initialize', success=True, message='', body={'supportsConditionalBreakpoints': True, 'supportsConfigurationDoneRequest': True, 'supportsDebuggerProperties': True, 'supportsEvaluateForHovers': True, 'supportsExceptionInfoRequest': True, 'supportsExceptionOptions': True, 'supportsHitConditionalBreakpoints': True, 'supportsLogPoints': True, 'supportsModulesRequest': True, 'supportsSetExpression': True, 'supportsSetVariable': True, 'supportsValueFormattingOptions': True, 'supportTerminateDebuggee': True, 'exceptionBreakpointFilters': [{'filter': 'raised', 'label': 'Raised Exceptions', 'default': False}, {'filter': 'uncaught', 'label': 'Uncaught Exceptions', 'default': True}]})
Event(seq=2, event='initialized', body={})
Response(seq=3, request_seq=1001, command='launch', success=True, message='', body={})
Event(seq=4, event='thread', body={'reason': 'started', 'threadId': 1})
Response(seq=5, request_seq=1002, command='threads', success=True, message='', body={'threads': [{'id': 1, 'name': 'MainThread'}]})
Response(seq=6, request_seq=1003, command='setBreakpoints', success=True, message='', body={'breakpoints': [{'id': 1, 'verified': True, 'line': 3}]})
Response(seq=7, request_seq=1004, command='configurationDone', success=True, message='', body={})
Event(seq=8, event='process', body={'name': '/var/folders/22/0kj01mp12l3dsd1vw9vhfs6c0000gn/T/workspace-2i58nezj/spam.py', 'systemProcessId': 1017, 'isLocalProcess': True, 'startMethod': 'launch'})
Event(seq=9, event='thread', body={'reason': 'started', 'threadId': 1})
```

As can be seen from the messages sent back by PTVSD, we have two events sent back for the exact same thread. Sequence `3` and `9`.

Clearly a bug somewhere in PTVSD.
This clearly impacts our unit tests. As we'd only expect a single thread creation event, not more.


Discussion:
Interesting, with VS I don't see two thread events. In VSC I see two thread events with same code.
```
 1> DebugAdapterHost version: 15.8.20619.1 commit:b4df29251b2ec944811f14aa956a3c64c599c136
 1> [DebugAdapter] --> C (initialize-1): {"command":"initialize","arguments":{"clientID":"visualstudio","clientName":"Visual Studio","adapterID":null,"locale":"en-US","linesStartAt1":true,"columnsStartAt1":true,"pathFormat":"path","supportsVariableType":true,"supportsRunInTerminalRequest":true,"supportsHandshakeRequest":true},"seq":1,"type":"request"}
 1> [DebugAdapter] <--   E (output): {"type": "event", "seq": 0, "event": "output", "body": {"category": "telemetry", "output": "ptvsd", "data": {"version": "4.1.1a9+0.gfb27b41.dirty"}}}
 1> [DebugAdapter] --> C (ptvsd_systemInfo-2): {"command":"ptvsd_systemInfo","arguments":{},"seq":2,"type":"request"}
 1> [DebugAdapter] <--   R (initialize-1): {"type": "response", "seq": 1, "request_seq": 1, "success": true, "command": "initialize", "message": "", "body": {"supportsConditionalBreakpoints": true, "supportsConfigurationDoneRequest": true, "supportsDebuggerProperties": true, "supportsEvaluateForHovers": true, "supportsExceptionInfoRequest": true, "supportsExceptionOptions": true, "supportsHitConditionalBreakpoints": true, "supportsLogPoints": true, "supportsModulesRequest": true, "supportsSetExpression": true, "supportsSetVariable": true, "supportsValueFormattingOptions": true, "supportTerminateDebuggee": true, "exceptionBreakpointFilters": [{"filter": "raised", "label": "Raised Exceptions", "default": false}, {"filter": "uncaught", "label": "Uncaught Exceptions", "default": true}]}}
 1> [DebugAdapter] <--   E (initialized): {"type": "event", "seq": 2, "event": "initialized", "body": {}}
 1> [DebugAdapter] --> C (launch-3): {"command":"launch","arguments":{"noDebug":false,"exe":"C:\\pyenv\\py3664\\Scripts\\python.exe","cwd":"C:\\Users\\kanadig\\source\\repos\\PyScratch\\PyScratch\\","remoteMachine":"","args":"C:\\Users\\kanadig\\source\\repos\\PyScratch\\PyScratch\\Scratch3.py","options":"WAIT_ON_ABNORMAL_EXIT=True;WAIT_ON_NORMAL_EXIT=True;REDIRECT_OUTPUT=True;DEBUG_STDLIB=True;VERSION=3.6;INTERPRETER_OPTIONS=","env":[]},"seq":3,"type":"request"}
 1> [DebugAdapter] <--   R (ptvsd_systemInfo-2): {"type": "response", "seq": 3, "request_seq": 2, "success": true, "command": "ptvsd_systemInfo", "message": "", "body": {"ptvsd": {"version": "4.1.1a9+0.gfb27b41.dirty"}, "python": {"version": "3.6.3final0", "implementation": {"name": "cpython", "version": "3.6.3final0", "description": "CPython"}}, "platform": {"name": "win32"}, "process": {"pid": 23832, "executable": "C:\\pyenv\\py3664\\Scripts\\python.exe", "bitness": 64}}}
 1> [DebugAdapter] <--   R (launch-3): {"type": "response", "seq": 4, "request_seq": 3, "success": true, "command": "launch", "message": "", "body": {}}
 1> [DebugAdapter] --> C (setDebuggerProperty-4): {"command":"setDebuggerProperty","arguments":{"DisableJITOptimization":0},"seq":4,"type":"request"}
 1> [DebugAdapter] <--   R (setDebuggerProperty-4): {"type": "response", "seq": 5, "request_seq": 4, "success": true, "command": "setDebuggerProperty", "message": "", "body": {}}
 1> [DebugAdapter] --> C (setDebuggerProperty-5): {"command":"setDebuggerProperty","arguments":{"InterpreterOptions":1},"seq":5,"type":"request"}
 1> [DebugAdapter] <--   R (setDebuggerProperty-5): {"type": "response", "seq": 6, "request_seq": 5, "success": true, "command": "setDebuggerProperty", "message": "", "body": {}}
 1> [DebugAdapter] --> C (setDebuggerProperty-6): {"command":"setDebuggerProperty","arguments":{"JustMyCodeStepping":1},"seq":6,"type":"request"}
 1> [DebugAdapter] <--   R (setDebuggerProperty-6): {"type": "response", "seq": 7, "request_seq": 6, "success": true, "command": "setDebuggerProperty", "message": "", "body": {}}
 1> [DebugAdapter] --> C (setDebuggerProperty-7): {"command":"setDebuggerProperty","arguments":{"StopOnExceptionCrossingManagedBoundary":0},"seq":7,"type":"request"}
 1> [DebugAdapter] <--   R (setDebuggerProperty-7): {"type": "response", "seq": 8, "request_seq": 7, "success": true, "command": "setDebuggerProperty", "message": "", "body": {}}
 1> [DebugAdapter] --> C (setDebuggerProperty-8): {"command":"setDebuggerProperty","arguments":{"WarnIfNoUserCodeOnLaunch":1},"seq":8,"type":"request"}
 1> [DebugAdapter] <--   R (setDebuggerProperty-8): {"type": "response", "seq": 9, "request_seq": 8, "success": true, "command": "setDebuggerProperty", "message": "", "body": {}}
 1> [DebugAdapter] --> C (setDebuggerProperty-9): {"command":"setDebuggerProperty","arguments":{"EnableStepFiltering":true},"seq":9,"type":"request"}
 1> [DebugAdapter] <--   R (setDebuggerProperty-9): {"type": "response", "seq": 10, "request_seq": 9, "success": true, "command": "setDebuggerProperty", "message": "", "body": {}}
 1> [DebugAdapter] --> C (setBreakpoints-10): {"command":"setBreakpoints","arguments":{"source":{"path":"c:\\Users\\kanadig\\source\\repos\\PyScratch\\PyScratch\\Scratch3.py","sources":[],"checksums":[]},"breakpoints":[{"line":15,"column":1}],"lines":[15]},"seq":10,"type":"request"}
 1> [DebugAdapter] --> C (setBreakpoints-11): {"command":"setBreakpoints","arguments":{"source":{"path":"c:\\Users\\kanadig\\source\\repos\\PyScratch\\PyScratch\\Scratch3.py","sources":[],"checksums":[]},"breakpoints":[{"line":15,"column":1}],"lines":[15]},"seq":11,"type":"request"}
 1> [DebugAdapter] --> C (setExceptionBreakpoints-12): {"command":"setExceptionBreakpoints","arguments":{"filters":[],"exceptionOptions":[{"path":[{"names":["Python Exceptions"]}],"breakMode":"userUnhandled"},{"path":[{"names":["Python Exceptions"]},{"names":["KeyError","AttributeError","IndexError","StopIteration","GeneratorExit"]}],"breakMode":"unhandled"}]},"seq":12,"type":"request"}
 1> [DebugAdapter] <--   R (setBreakpoints-10): {"type": "response", "seq": 11, "request_seq": 10, "success": true, "command": "setBreakpoints", "message": "", "body": {"breakpoints": [{"id": 1, "verified": true, "line": 15}]}}
 1> [DebugAdapter] <--   R (setBreakpoints-11): {"type": "response", "seq": 12, "request_seq": 11, "success": true, "command": "setBreakpoints", "message": "", "body": {"breakpoints": [{"id": 2, "verified": true, "line": 15}]}}
 1> [DebugAdapter] <--   R (setExceptionBreakpoints-12): {"type": "response", "seq": 13, "request_seq": 12, "success": true, "command": "setExceptionBreakpoints", "message": "", "body": {}}
 1> [DebugAdapter] --> C (configurationDone-13): {"command":"configurationDone","arguments":{},"seq":13,"type":"request"}
 1> [DebugAdapter] <--   R (configurationDone-13): {"type": "response", "seq": 14, "request_seq": 13, "success": true, "command": "configurationDone", "message": "", "body": {}}
 1> [DebugAdapter] <--   E (process): {"type": "event", "seq": 15, "event": "process", "body": {"name": "C:\\Users\\kanadig\\source\\repos\\PyScratch\\PyScratch\\Scratch3.py", "systemProcessId": 23832, "isLocalProcess": true, "startMethod": "launch"}}
 1> [DebugAdapter] <--   E (thread): {"type": "event", "seq": 16, "event": "thread", "body": {"reason": "started", "threadId": 1}}
 1> [DebugAdapter] <--   E (output): {"type": "event", "seq": 17, "event": "output", "body": {"category": "stdout", "output": "Created event: pid_23832_id_1549505340696"}}
 1> [DebugAdapter] <--   E (output): {"type": "event", "seq": 18, "event": "output", "body": {"category": "stdout", "output": "\n"}}
 1> [DebugAdapter] <--   E (stopped): {"type": "event", "seq": 19, "event": "stopped", "body": {"reason": "breakpoint", "threadId": 1, "text": null, "description": null}}
 1> [DebugAdapter] --> C (threads-14): {"command":"threads","arguments":{},"seq":14,"type":"request"}
 1> [DebugAdapter] <--   E (output): {"type": "event", "seq": 20, "event": "output", "body": {"category": "stdout", "output": "Threads: pid_23832_id_1549505340696"}}
 1> [DebugAdapter] <--   E (output): {"type": "event", "seq": 21, "event": "output", "body": {"category": "stdout", "output": "\n"}}
 1> [DebugAdapter] <--   R (threads-14): {"type": "response", "seq": 22, "request_seq": 14, "success": true, "command": "threads", "message": "", "body": {"threads": [{"id": 1, "name": "MainThread"}]}}
 1> [DebugAdapter] --> C (stackTrace-15): {"command":"stackTrace","arguments":{"threadId":1,"startFrame":0,"levels":1,"format":{"includeAll":true}},"seq":15,"type":"request"}
 1> [DebugAdapter] <--   E (output): {"type": "event", "seq": 23, "event": "output", "body": {"category": "stdout", "output": "Translations: [('pid_23832_id_1549505340696', 1)]"}}
 1> [DebugAdapter] <--   E (output): {"type": "event", "seq": 24, "event": "output", "body": {"category": "stdout", "output": "\n"}}
 1> [DebugAdapter] <--   E (module): {"type": "event", "seq": 25, "event": "module", "body": {"reason": "new", "module": {"id": 1, "package": null, "path": "c:\\users\\kanadig\\source\\repos\\pyscratch\\pyscratch\\scratch3.py", "name": "__main__"}}}
 1> [DebugAdapter] <--   R (stackTrace-15): {"type": "response", "seq": 26, "request_seq": 15, "success": true, "command": "stackTrace", "message": "", "body": {"stackFrames": [{"id": 1, "name": "<module>", "source": {"path": "c:\\users\\kanadig\\source\\repos\\pyscratch\\pyscratch\\scratch3.py", "sourceReference": 0}, "line": 15, "column": 1}], "totalFrames": 1}}
 1> [DebugAdapter] --> C (stackTrace-16): {"command":"stackTrace","arguments":{"threadId":1,"startFrame":0,"levels":1000,"format":{"parameters":true,"parameterTypes":true,"parameterNames":true,"line":true,"module":true}},"seq":16,"type":"request"}
 1> [DebugAdapter] <--   R (stackTrace-16): {"type": "response", "seq": 27, "request_seq": 16, "success": true, "command": "stackTrace", "message": "", "body": {"stackFrames": [{"id": 1, "name": "__main__ : 15", "source": {"path": "c:\\users\\kanadig\\source\\repos\\pyscratch\\pyscratch\\scratch3.py", "sourceReference": 0}, "line": 15, "column": 1}], "totalFrames": 1}}
 1> [DebugAdapter] --> C (scopes-17): {"command":"scopes","arguments":{"frameId":1},"seq":17,"type":"request"}
 1> [DebugAdapter] <--   R (scopes-17): {"type": "response", "seq": 28, "request_seq": 17, "success": true, "command": "scopes", "message": "", "body": {"scopes": [{"name": "Locals", "expensive": false, "variablesReference": 1}]}}
 1> [DebugAdapter] --> C (variables-18): {"command":"variables","arguments":{"variablesReference":1,"timeout":1000},"seq":18,"type":"request"}
 1> [DebugAdapter] <--   R (variables-18): {"type": "response", "seq": 29, "request_seq": 18, "success": true, "command": "variables", "message": "", "body": {"variables": [{"name": "QApplication", "type": "wrappertype", "value": "<class 'PyQt5.QtWidgets.QApplication'>", "variablesReference": 2}, {"name": "QLabel", "type": "wrappertype", "value": "<class 'PyQt5.QtWidgets.QLabel'>", "variablesReference": 3}, {"name": "QObject", "type": "wrappertype", "value": "<class 'PyQt5.QtCore.QObject'>", "variablesReference": 4}, {"name": "QPushButton", "type": "wrappertype", "value": "<class 'PyQt5.QtWidgets.QPushButton'>", "variablesReference": 5}, {"name": "QTextEdit", "type": "wrappertype", "value": "<class 'PyQt5.QtWidgets.QTextEdit'>", "variablesReference": 6}, {"name": "QThread", "type": "wrappertype", "value": "<class 'PyQt5.QtCore.QThread'>", "variablesReference": 7}, {"name": "QVBoxLayout", "type": "wrappertype", "value": "<class 'PyQt5.QtWidgets.QVBoxLayout'>", "variablesReference": 8}, {"name": "QWidget", "type": "wrappertype", "value": "<class 'PyQt5.QtWidgets.QWidget'>", "variablesReference": 9}, {"name": "f", "type": "TextIOWrapper", "value": "<_io.TextIOWrapper name='sampleJSON.json' mode='r' encoding='cp1252'>", "variablesReference": 12}, {"name": "pyqtSignal", "type": "type", "value": "<class 'PyQt5.QtCore.pyqtSignal'>", "variablesReference": 13}, {"name": "pyqtSlot", "type": "builtin_function_or_method", "value": "<built-in function pyqtSlot>", "variablesReference": 14}, {"name": "sys", "type": "module", "value": "<module 'sys' (built-in)>", "variablesReference": 15}, {"name": "text", "type": "str", "value": "'{\\n  \"web-app\": {\\n    \"servlet\": [\\n      {\\n        \"servlet-name\": \"cofaxCDS\",\\n        \"servlet-class\": \"org.cofax.cds.CDSServlet\",\\n        \"init-param\": {\\n          \"configGlossary:installationAt\": \"Philadelphia, PA\",\\n          \"configGlossary:adminEmail\": \"ksm@pobox.com\",\\n          \"configGlossary:poweredBy\": \"Cofax\",\\n          \"configGlossary:poweredByIcon\": \"/images/cofax.gif\",\\n          \"configGlossary:staticPath\": \"/content/static\",\\n          \"templateProcessorClass\": \"org.cofax.WysiwygTemplate\",\\n          \"templateLoaderClass\": \"org.cofax.FilesTemplateLoader\",\\n          \"templatePath\": \"templates\",\\n          \"templateOverridePath\": \"\",\\n          \"defaultListTemplate\": \"listTemplate.htm\",\\n          \"defaultFileTemplate\": \"articleTemplate.htm\",\\n          \"useJSP\": false,\\n          \"jspListTemplate\": \"listTemplate.jsp\",\\n          \"jspFileTemplate\": \"articleTemplate.jsp\",\\n          \"cachePackageTagsTrack\": 200,\\n          \"cachePackageTagsStore\": 200,\\n          \"cachePackageTagsRefresh\": 60,\\n          \"cacheTemplatesTrack\": 100,\\n          \"cacheTemplatesStore\": 50,\\n          \"cacheTemplatesRefresh\": 15,\\n          \"cachePagesTrack\": 200,\\n          \"cachePagesStore\": 100,\\n          \"cachePagesRefresh\": 10,\\n          \"cachePagesDirtyRead\": 10,\\n          \"searchEngineListTemplate\": \"forSearchEnginesList.htm\",\\n          \"searchEngineFileTemplate\": \"forSearchEngines.htm\",\\n          \"searchEngineRobotsDb\": \"WEB-INF/robots.db\",\\n          \"useDataStore\": true,\\n          \"dataStoreClass\": \"org.cofax.SqlDataStore\",\\n          \"redirectionClass\": \"org.cofax.SqlRedirection\",\\n          \"dataStoreName\": \"cofax\",\\n          \"dataStoreDriver\": \"com.microsoft.jdbc.sqlserver.SQLServerDriver\",\\n          \"dataStoreUrl\": \"jdbc:microsoft:sqlserver://LOCALHOST:1433;DatabaseName=goon\",\\n          \"dataStoreUser\": \"sa\",\\n          \"dataStorePassword\": \"dataStoreTestQuery\",\\n          \"dataStoreTestQuery\": \"SET NOCOUNT ON;select test=\\'test\\';\",\\n          \"dataStoreLogFile\": \"/usr/local/tomcat/logs/datastore.log\",\\n          \"dataStoreInitConns\": 10,\\n          \"dataStoreMaxConns\": 100,\\n          \"dataStoreConnUsageLimit\": 100,\\n          \"dataStoreLogLevel\": \"debug\",\\n          \"maxUrlLength\": 500\\n        }\\n      },\\n      {\\n        \"servlet-name\": \"cofaxEmail\",\\n        \"servlet-class\": \"org.cofax.cds.EmailServlet\",\\n        \"init-param\": {\\n          \"mailHost\": \"mail1\",\\n          \"mailHostOverride\": \"mail2\"\\n        }\\n      },\\n      {\\n        \"servlet-name\": \"cofaxAdmin\",\\n        \"servlet-class\": \"org.cofax.cds.AdminServlet\"\\n      },\\n\\n      {\\n        \"servlet-name\": \"fileServlet\",\\n        \"servlet-class\": \"org.cofax.cds.FileServlet\"\\n      },\\n      {\\n        \"servlet-name\": \"cofaxTools\",\\n        \"servlet-class\": \"org.cofax.cms.CofaxToolsServlet\",\\n        \"init-param\": {\\n          \"templatePath\": \"toolstemplates/\",\\n          \"log\": 1,\\n          \"logLocation\": \"/usr/local/tomcat/logs/CofaxTools.log\",\\n          \"logMaxSize\": \"\",\\n          \"dataLog\": 1,\\n          \"dataLogLocation\": \"/usr/local/tomcat/logs/dataLog.log\",\\n          \"dataLogMaxSize\": \"\",\\n          \"removePageCache\": \"/content/admin/remove?cache=pages&id=\",\\n          \"removeTemplateCache\": \"/content/admin/remove?cache=templates&id=\",\\n          \"fileTransferFolder\": \"/usr/local/tomcat/webapps/content/fileTransferFolder\",\\n          \"lookInContext\": 1,\\n          \"adminGroupID\": 4,\\n          \"betaServer\": true\\n        }\\n      }\\n    ],\\n    \"servlet-mapping\": {\\n      \"cofaxCDS\": \"/\",\\n      \"cofaxEmail\": \"/cofaxutil/aemail/*\",\\n      \"cofaxAdmin\": \"/admin/*\",\\n      \"fileServlet\": \"/static/*\",\\n      \"cofaxTools\": \"/tools/*\"\\n    },\\n\\n    \"taglib\": {\\n      \"taglib-uri\": \"cofax.tld\",\\n      \"taglib-location\": \"/WEB-INF/tlds/cofax.tld\"\\n    }\\n  }\\n}\\n'", "presentationHint": {"attributes": ["rawString"]}}, {"name": "time", "type": "module", "value": "<module 'time' (built-in)>", "variablesReference": 16}, {"name": "__builtins__", "type": "dict", "value": "{'ArithmeticError': <class 'ArithmeticError'>, 'AssertionError': <class 'AssertionError'>, 'AttributeError': <class 'AttributeError'>, 'BaseException': <class 'BaseException'>, 'BlockingIOError': <class 'BlockingIOError'>, 'BrokenPipeError': <class 'BrokenPipeError'>, 'BufferError': <class 'BufferError'>, 'BytesWarning': <class 'BytesWarning'>, 'ChildProcessError': <class 'ChildProcessError'>, 'ConnectionAbortedError': <class 'ConnectionAb...tedError'>, 'ConnectionError': <class 'ConnectionError'>, 'ConnectionRefusedError': <class 'ConnectionRe...sedError'>, 'ConnectionResetError': <class 'ConnectionResetError'>, 'DeprecationWarning': <class 'DeprecationWarning'>, ...}", "variablesReference": 10}, {"name": "__doc__", "type": "NoneType", "value": "None"}, {"name": "__file__", "type": "str", "value": "'C:\\\\Users\\\\kanadig\\\\source\\\\repos\\\\PyScratch\\\\PyScratch\\\\Scratch3.py'", "presentationHint": {"attributes": ["rawString"]}}, {"name": "__loader__", "type": "SourceFileLoader", "value": "<_frozen_importlib_external.SourceFileLoader object at 0x00000168C617D860>", "variablesReference": 11}, {"name": "__name__", "type": "str", "value": "'__main__'", "presentationHint": {"attributes": ["rawString"]}}, {"name": "__package__", "type": "NoneType", "value": "None"}, {"name": "__spec__", "type": "NoneType", "value": "None"}]}}
```
See Sequence `16`

Resolving patch:
diff --git a/ptvsd/wrapper.py b/ptvsd/wrapper.py
--- a/ptvsd/wrapper.py
+++ b/ptvsd/wrapper.py
@@ -1188,6 +1188,7 @@ def __init__(self, socket, pydevd_notify, pydevd_request,
         self.exceptions_mgr = ExceptionsManager(self)
         self.modules_mgr = ModulesManager(self)
         self.internals_filter = InternalsFilter()
+        self.new_thread_lock = threading.Lock()
 
         # adapter state
         self.path_casing = PathUnNormcase()
@@ -1470,23 +1471,26 @@ def on_threads(self, request, args):
             xthreads = []
 
         threads = []
-        for xthread in xthreads:
-            try:
-                name = unquote(xthread['name'])
-            except KeyError:
-                name = None
-
-            if not is_debugger_internal_thread(name):
-                pyd_tid = xthread['id']
+        with self.new_thread_lock:
+            for xthread in xthreads:
                 try:
-                    vsc_tid = self.thread_map.to_vscode(pyd_tid, autogen=False)
+                    name = unquote(xthread['name'])
                 except KeyError:
-                    # This is a previously unseen thread
-                    vsc_tid = self.thread_map.to_vscode(pyd_tid, autogen=True)
-                    self.send_event('thread', reason='started',
-                                    threadId=vsc_tid)
+                    name = None
 
-                threads.append({'id': vsc_tid, 'name': name})
+                if not is_debugger_internal_thread(name):
+                    pyd_tid = xthread['id']
+                    try:
+                        vsc_tid = self.thread_map.to_vscode(pyd_tid,
+                                                            autogen=False)
+                    except KeyError:
+                        # This is a previously unseen thread
+                        vsc_tid = self.thread_map.to_vscode(pyd_tid,
+                                                            autogen=True)
+                        self.send_event('thread', reason='started',
+                                        threadId=vsc_tid)
+
+                    threads.append({'id': vsc_tid, 'name': name})
 
         self.send_response(request, threads=threads)
 
@@ -2210,9 +2214,17 @@ def on_pydevd_thread_create(self, seq, args):
         except KeyError:
             name = None
         if not is_debugger_internal_thread(name):
-            # Any internal pydevd or ptvsd threads will be ignored everywhere
-            tid = self.thread_map.to_vscode(xml.thread['id'], autogen=True)
-            self.send_event('thread', reason='started', threadId=tid)
+            with self.new_thread_lock:
+                pyd_tid = xml.thread['id']
+                # Any internal pydevd or ptvsd threads will be ignored
+                # everywhere
+                try:
+                    tid = self.thread_map.to_vscode(pyd_tid,
+                                                    autogen=False)
+                except KeyError:
+                    tid = self.thread_map.to_vscode(pyd_tid,
+                                                    autogen=True)
+                    self.send_event('thread', reason='started', threadId=tid)
 
     @pydevd_events.handler(pydevd_comm.CMD_THREAD_KILL)
     def on_pydevd_thread_kill(self, seq, args):


Test patch:
diff --git a/tests/highlevel/test_live_pydevd.py b/tests/highlevel/test_live_pydevd.py
--- a/tests/highlevel/test_live_pydevd.py
+++ b/tests/highlevel/test_live_pydevd.py
@@ -311,9 +311,8 @@ def test_breakpoints_single_file(self):
             with self.launched(config=config):
                 with self.fix.hidden():
                     _, tid = self.get_threads(self.thread.name)
-                with self.wait_for_event('thread'):
-                    with self.wait_for_event('stopped'):
-                        done1()
+                with self.wait_for_event('stopped'):
+                    done1()
                 with self.wait_for_event('stopped'):
                     with self.wait_for_event('continued'):
                         req_continue1 = self.send_request('continue', {
diff --git a/tests/system_tests/test_main.py b/tests/system_tests/test_main.py
--- a/tests/system_tests/test_main.py
+++ b/tests/system_tests/test_main.py
@@ -686,11 +686,6 @@ def test_detach_clear_and_resume(self):
                     'verified': True,
                 }],
             }),
-            self.new_event(
-                'thread',
-                threadId=tid1,
-                reason='started',
-            ),
             self.new_event(
                 'stopped',
                 threadId=tid1,
@@ -955,11 +950,6 @@ def test_attach_breakpoints(self):
                 'startMethod': 'attach',
                 'name': filename,
             }),
-            self.new_event(
-                'thread',
-                threadId=tid,
-                reason='started',
-            ),
             self.new_event(
                 'stopped',
                 threadId=tid,