Mail Archives: cygwin/2018/02/14/02:04:27
X-Recipient: | archive-cygwin AT delorie DOT com
|
DomainKey-Signature: | a=rsa-sha1; c=nofws; d=sourceware.org; h=list-id
|
| :list-unsubscribe:list-subscribe:list-archive:list-post
|
| :list-help:sender:date:from:reply-to:reply-to:to:message-id
|
| :in-reply-to:references:subject:mime-version:content-type
|
| :content-transfer-encoding; q=dns; s=default; b=oiLy4NmalgAb6lC2
|
| CIbilTs4D8qYJyqo0daxr24N1zTIiSI9SBy+WkJS+fZHj5lqBd0JgLPo5RIhlzCP
|
| 9LDAQ+25C25camcyjo7CdVS/RlZZpZaDmPqGS+PA77UqJjjTUGAF34ypvf3LfzCm
|
| IG5NncSxLAFK/2W8aBn1SbH4V6Q=
|
DKIM-Signature: | v=1; a=rsa-sha1; c=relaxed; d=sourceware.org; h=list-id
|
| :list-unsubscribe:list-subscribe:list-archive:list-post
|
| :list-help:sender:date:from:reply-to:reply-to:to:message-id
|
| :in-reply-to:references:subject:mime-version:content-type
|
| :content-transfer-encoding; s=default; bh=x9uflVGFHyOsOY/ThqA/Dz
|
| 6I0o4=; b=gbsKcIAuK97XFgmLVWX4ntNmk9pXlDy7R2fF3ux/wjnd7FSaTqjUpo
|
| M1BgHoBQEwGXPsz9EBFIZjhGK486uTMrcHAEzcRR2AJBJOqda7lfazCEG11kLPJG
|
| SfaFFuEG2wak8swd68yhDg2dbPWjmi9p3nQYoe3Yl7OweoTGnsvuQ=
|
Mailing-List: | contact cygwin-help AT cygwin DOT com; run by ezmlm
|
List-Id: | <cygwin.cygwin.com>
|
List-Subscribe: | <mailto:cygwin-subscribe AT cygwin DOT com>
|
List-Archive: | <http://sourceware.org/ml/cygwin/>
|
List-Post: | <mailto:cygwin AT cygwin DOT com>
|
List-Help: | <mailto:cygwin-help AT cygwin DOT com>, <http://sourceware.org/ml/#faqs>
|
Sender: | cygwin-owner AT cygwin DOT com
|
Mail-Followup-To: | cygwin AT cygwin DOT com
|
Delivered-To: | mailing list cygwin AT cygwin DOT com
|
Authentication-Results: | sourceware.org; auth=none
|
X-Virus-Found: | No
|
X-Spam-SWARE-Status: | No, score=2.4 required=5.0 tests=AWL,BAYES_00,FREEMAIL_ENVFROM_END_DIGIT,FREEMAIL_FROM,FREEMAIL_REPLYTO_END_DIGIT,HTML_MESSAGE,RCVD_IN_DNSWL_NONE,SPF_PASS,T_RP_MATCHES_RCVD autolearn=no version=3.3.2 spammy=H*x:KHTML, H*x:Chrome, H*x:AppleWebKit, H*x:Safari
|
X-HELO: | sonic301-20.consmr.mail.gq1.yahoo.com
|
Date: | Wed, 14 Feb 2018 07:04:03 +0000 (UTC)
|
From: | "Xiaofeng Liu via cygwin" <cygwin AT cygwin DOT com>
|
Reply-To: | Xiaofeng Liu <liuxf09 AT yahoo DOT com>
|
Reply-To: | Xiaofeng Liu <liuxf09 AT yahoo DOT com>
|
To: | "cygwin AT cygwin DOT com" <cygwin AT cygwin DOT com>
|
Message-ID: | <1460534026.545542.1518591843449@mail.yahoo.com>
|
In-Reply-To: | <1264797847.540865.1518590850864@mail.yahoo.com>
|
References: | <1543396632 DOT 5417641 DOT 1512146709346 DOT ref AT mail DOT yahoo DOT com> <1543396632 DOT 5417641 DOT 1512146709346 AT mail DOT yahoo DOT com> <20171201171536 DOT GA4325 AT calimero DOT vinschen DOT de> <1264797847 DOT 540865 DOT 1518590850864 AT mail DOT yahoo DOT com>
|
Subject: | Re: mixed usage of lock protection and lock-free List template class in thread.h
|
MIME-Version: | 1.0
|
X-MIME-Autoconverted: | from quoted-printable to 8bit by delorie.com id w1E74ORU009815
|
Sorry I have to reformat again.
Here is the sample code that will hang in cygwin:
test-thread.cpp
to compile:Â g++ -std=c++0x test-thread.cpp -lpthread
#include <stdio.h>#include <stdlib.h>#include <thread>#include <vector>#include <string>#include <ctime>#include <climits>#include <cassert>#include <mutex>
#include <condition_variable>#include <deque>#include <mutex>#include <pthread.h>#include <cstdint>using namespace std;
template<class T>class Queue {Â Â typedef std::deque<T*> Container;public:Â Â Queue(int _capacity = std::numeric_limits<int>::max()) : capacity(_capacity), closed(false) {}Â Â bool enqueue(T* d)Â Â {Â Â Â Â if (closed) return false;Â Â Â Â std::unique_lock<std::mutex> lock(mutex);Â Â Â Â if (d == 0) { closed = true; empty_cv.notify_all(); return true; }Â Â Â Â while (data.size() >= capacity)Â Â Â Â Â Â full_cv.wait(lock);Â Â Â Â data.push_back(d);Â Â Â Â empty_cv.notify_one();Â Â Â Â return true;Â Â }Â Â T* dequeue()Â Â {Â Â Â Â std::unique_lock<std::mutex> lock(mutex);Â Â Â Â while (data.empty() && !closed)Â Â Â Â Â Â empty_cv.wait(lock);Â Â Â Â if (data.size()) {Â Â Â Â Â Â T* d = data.front();Â Â Â Â Â Â data.pop_front();Â Â Â Â Â Â full_cv.notify_one();Â Â Â Â Â Â return d;Â Â Â Â } else return 0;Â Â }Â Â size_t size() const { return data.size(); }
private:Â Â std::mutex mutex;Â Â std::condition_variable full_cv, empty_cv;Â Â uint32_t capacity;Â Â bool closed;Â Â Container data;};
struct Node {Â Â int data;};
struct Job {Â Â Node* node;Â Â Queue<Node>* recycle;};
static Queue<Job> jobs;
static void* handle_job(void* arg){Â Â long ithr = (long)arg;Â Â unsigned long seed = time(0) + ithr*1000000;Â Â int NS = 1000;Â Â while (Job* j = jobs.dequeue()) {Â Â Â Â struct timespec ts;Â Â Â Â ts.tv_sec = 0;Â Â Â Â seed = seed * 1103515245 + 12345;Â Â Â Â ts.tv_nsec = seed%NS;Â Â Â Â nanosleep(&ts, 0);Â Â Â Â j->recycle->enqueue(j->node);Â Â Â Â delete j;Â Â }}
struct Task {  Queue<Node> recycle;  int size; // number of sub jobs  Task(int N) : size(N)  {    for (int i = 0; i<N; ++i) {      Node* t = new Node();      t->data = i;      Job* job = new Job;      job->node = t;      job->recycle = &recycle;      jobs.enqueue(job);    }  }  ~Task()  {    int i = 0;    while (Node* t = recycle.dequeue()) {      delete t;      if (++i == size) break;    }  }};
static string timestamp(){Â Â time_t t;Â Â struct tm tmp;Â Â char buf[80];Â Â t = time(NULL);Â Â localtime_r(&t, &tmp);Â Â strftime(buf, sizeof(buf), "%d-%m-%Y %I:%M:%S", &tmp);Â Â return buf;}
static void* create_task(void* arg){Â Â long ithr = (long)arg;Â Â int TASK_NUM = 1000000;Â Â int one_percent = TASK_NUM/100;Â Â int TASK_SUB_JOB_NUM = 1;Â Â int NS = 1000;Â Â unsigned long seed = time(0) + ithr*10000;Â Â int i = 0;Â Â for (; i < TASK_NUM; ++i) {Â Â Â Â struct timespec ts;Â Â Â Â ts.tv_sec = 0;Â Â Â Â seed = seed * 1103515245 + 12345;Â Â Â Â ts.tv_nsec = seed%NS;Â Â Â Â nanosleep(&ts, 0);Â Â Â Â if (i%one_percent == 0) {Â Â Â Â Â Â fprintf(stderr, "%s: create_task[%d]: %d%% done\n", timestamp().c_str(), ithr, i/one_percent);Â Â Â Â }Â Â Â Â Task task(TASK_SUB_JOB_NUM);Â Â }Â Â fprintf(stderr, "%s: create_task[%d]: %d%% done\n", timestamp().c_str(), ithr, i/one_percent);}
int main(){  int NTHR_HANDLE_JOB = 4, NTHR_CREATE_TASK = 4;  std::vector<pthread_t> threads(NTHR_HANDLE_JOB+NTHR_CREATE_TASK);  int k = 0;  for (long i = 0; i < NTHR_HANDLE_JOB; ++i) {    pthread_create(&threads[k++], NULL, handle_job, (void*)i);  }  for (long i = 0; i < NTHR_CREATE_TASK; ++i) {    pthread_create(&threads[k++], NULL, create_task, (void*)i);  }  // wait for create_task thread  for (size_t i = NTHR_HANDLE_JOB; i < threads.size(); ++i) {    pthread_join(threads[i], NULL);  }  jobs.enqueue(0);  // wait for handle_job thread  for (size_t i = 0; i < NTHR_HANDLE_JOB; ++i)    pthread_join(threads[i], NULL);}
In this code, mutex and cond need be created and destroyed very frequently, which could corrupt the static list object owned by some classes in thread.h. In my test, I have a computer of 8 threads to run cygwin, and the hang could happen when cond/mutex objects are created and destroyed for the order of 1 millions times within a few minutes.
I can also observe that the peak memory kept increasing to a few hundred MB, and I suspect there is a MEMORY LEAK in cygwin kernel.Â
I hope the format will be good. If not, I will try again.
Thanks.Â
Xiaofeng
From: Corinna Vinschen <corinna-cygwin AT cygwin DOT com>
To: cygwin AT cygwin DOT com
Sent: Friday, December 1, 2017 9:15 AM
Subject: Re: mixed usage of lock protection and lock-free List template class in thread.h
On Dec 1 16:45, Xiaofeng Liu via cygwin wrote:
> Lock protection and lock-free should never be mixed !Â
> ​https://cygwin.com/git/gitweb.cgi?p=newlib-cygwin.git;a=blob;f=winsup/cygwin/thread.h;hb=1f42dc2bcf58d3b8629eb13d53de3f69fc314b47#l110
>
>  110 template <class list_node> inline void 111 List_insert (list_node *&head, list_node *node) 112 { 113  if (!node) 114   return; 115  do 116   node->next = head; 117  while (InterlockedCompareExchangePointer ((PVOID volatile *) &head, 118                       node, node->next) != node->next); 119 } 120  121 template <class list_node> inline void 122 List_remove (fast_mutex &mx, list_node *&head, list_node *node) 123 { 124  if (!node) 125   return; 126  mx.lock (); 127  if (head) 128   { 129    if (InterlockedCompareExchangePointer ((PVOID volatile *) &head, 130                       node->next, node) != node) 131     { 132      list_node *cur = head; 133  134      while (cur->next && node != cur->next) 135       cur = cur->next; 136      if (node == cur->next) 137       cur->next = cur->next->next; 138     } 139   } 140  mx.unlock (); 141 }
> The symptom I met is a job hang with the following stack:
> #0Â 0x000000007711c2ea in ntdll!ZwWaitForMultipleObjects () from /cygdrive/c/Windows/SYSTEM32/ntdll.dll
> #1Â 0x000007fefd111430 in KERNELBASE!GetCurrentProcess () from /cygdrive/c/Windows/system32/KERNELBASE.dll
> #2Â 0x0000000076fc06c0 in WaitForMultipleObjects () from /cygdrive/c/Windows/system32/kernel32.dll
> #3Â 0x00000001800458ac in cygwait(void*, _LARGE_INTEGER*, unsigned int) () from /usr/bin/cygwin1.dll
> #4Â 0x000000018013d029 in pthread_cond::~pthread_cond() () from /usr/bin/cygwin1.dll
> #5Â 0x000000018013d0dd in pthread_cond::~pthread_cond() () from /usr/bin/cygwin1.dll
> #6Â 0x0000000180141196 in pthread_cond_destroy () from /usr/bin/cygwin1.dll
> #7Â 0x0000000180116d5b in _sigfe () from /usr/bin/cygwin1.dll
> #8Â 0x0000000100908e38 in std::_Sp_counted_ptr_inplace<std::__future_base::_Task_state<std::function<void ()>, std::allocator<int>, void ()>, std::allocator<int>, (__gnu_cxx::_Lock_policy)2>::_M_dispose() ()
> The problem with the current implementation for concurrent insert and delete is explained at WikipediaNon-blocking linked list
>
> My question is how to solve this ? Adding lock protection in List_insert (removing lock-freee) or implementing a complete lock-free List based on Harris's solution to use two CAS?
First of all, please, please, please fix your MUA! Just like your
mails to cygwin-patches a couple of weeks ago, your mails are pretty
much unreadable due to broken line wrapping.
Back to business: This code is working since 2003. So, is that just
a theoretical problem, or a practical one? If the latter, what is
broken exactly?
However, since you're asking, a lockless implementation where appropriate
is always welcome.
Thanks,
Corinna
--
Corinna Vinschen         Please, send mails regarding Cygwin to
Cygwin Maintainer        cygwin AT cygwin DOT com
Red Hat
--
Problem reports: http://cygwin.com/problems.html
FAQ: http://cygwin.com/faq/
Documentation: http://cygwin.com/docs.html
Unsubscribe info: http://cygwin.com/ml/#unsubscribe-simple
- Raw text -