Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > comp.lang.c > #103784 > unrolled thread

Memory not updating in thread as expected

Started byTest <test@.nil.invalid.com>
First post2017-02-13 12:46 +0200
Last post2017-02-14 16:37 -0800
Articles 20 on this page of 28 — 12 participants

Back to article view | Back to comp.lang.c


Contents

  Memory not updating in thread as expected Test <test@.nil.invalid.com> - 2017-02-13 12:46 +0200
    Re: Memory not updating in thread as expected m.labanowicz@gmail.com - 2017-02-13 05:18 -0800
      Re: Memory not updating in thread as expected Test <test@.nil.invalid.com> - 2017-02-13 16:25 +0200
        Re: Memory not updating in thread as expected m.labanowicz@gmail.com - 2017-02-13 10:30 -0800
          Re: Memory not updating in thread as expected Jerry Stuckle <jstucklex@attglobal.net> - 2017-02-13 14:30 -0500
    Re: Memory not updating in thread as expected m.labanowicz@gmail.com - 2017-02-13 05:46 -0800
      Re: Memory not updating in thread as expected Ben Bacarisse <ben.usenet@bsb.me.uk> - 2017-02-13 14:30 +0000
        Re: Memory not updating in thread as expected "Chris M. Thomasson" <invalid@invalid.invalid> - 2017-02-13 15:13 -0800
      Re: Memory not updating in thread as expected Test <test@.nil.invalid.com> - 2017-02-13 16:36 +0200
        Re: Memory not updating in thread as expected David Brown <david.brown@hesbynett.no> - 2017-02-13 23:15 +0100
          Re: Memory not updating in thread as expected James Kuyper <jameskuyper@verizon.net> - 2017-02-13 22:04 -0500
            Re: Memory not updating in thread as expected David Brown <david.brown@hesbynett.no> - 2017-02-14 09:44 +0100
              Re: Memory not updating in thread as expected Ben Bacarisse <ben.usenet@bsb.me.uk> - 2017-02-14 11:07 +0000
                Re: Memory not updating in thread as expected David Brown <david.brown@hesbynett.no> - 2017-02-14 12:46 +0100
                  Re: Memory not updating in thread as expected Robert Wessel <robertwessel2@yahoo.com> - 2017-02-16 05:12 -0600
                    Re: Memory not updating in thread as expected David Brown <david.brown@hesbynett.no> - 2017-02-16 12:44 +0100
                Re: Memory not updating in thread as expected Alain Ketterlin <alain@universite-de-strasbourg.fr.invalid> - 2017-02-14 15:53 +0100
                  Re: Memory not updating in thread as expected Ben Bacarisse <ben.usenet@bsb.me.uk> - 2017-02-14 15:36 +0000
                    Re: Memory not updating in thread as expected Alain Ketterlin <alain@universite-de-strasbourg.fr.invalid> - 2017-02-14 17:58 +0100
                      Re: Memory not updating in thread as expected Ben Bacarisse <ben.usenet@bsb.me.uk> - 2017-02-14 17:26 +0000
            Re: Memory not updating in thread as expected Alain Ketterlin <alain@universite-de-strasbourg.fr.invalid> - 2017-02-14 10:43 +0100
              Re: Memory not updating in thread as expected Robert Wessel <robertwessel2@yahoo.com> - 2017-02-14 03:52 -0600
                Re: Memory not updating in thread as expected Alain Ketterlin <alain@universite-de-strasbourg.fr.invalid> - 2017-02-14 11:36 +0100
                Re: Memory not updating in thread as expected supercat@casperkitty.com - 2017-02-14 05:31 -0800
    Re: Memory not updating in thread as expected Ken Brody <kenbrody@spamcop.net> - 2017-02-13 12:44 -0500
    Re: Memory not updating in thread as expected Joe Pfeiffer <pfeiffer@cs.nmsu.edu> - 2017-02-13 10:58 -0700
    Re: Memory not updating in thread as expected "Chris M. Thomasson" <invalid@invalid.invalid> - 2017-02-14 15:13 -0800
      Re: Memory not updating in thread as expected "Chris M. Thomasson" <invalid@invalid.invalid> - 2017-02-14 16:37 -0800

Page 1 of 2  [1] 2  Next page →


#103784 — Memory not updating in thread as expected

FromTest <test@.nil.invalid.com>
Date2017-02-13 12:46 +0200
SubjectMemory not updating in thread as expected
Message-ID<s023ac5gl1bpefvi63upl7tb6iunf0a8mo@4ax.com>
In my (linux) c code I create a thread which allocates a string, say:

.. in the thread function:
str1=alloc(50);
str1[0]=50;
while (str1[0]==50)
  {
  sleep(1);
  }
str1[0]=2; // signal main program that I'm out of teh loop and about to finish
return;
} 

..

The thread function passes the address of "str1" to the main program.
When the main program want to end the thread it changes the str1[0] to zero and
wait it to change to 2 (str2When the loop in the thread exits it changes

...main program:
// str2 has the address of str1 in the thread, ie. (long)str1==(long)str2
str2[0]=0;  // signal thread that it should exit the loop
printf("%d\n",(int)str2[0]);   // "0" is shown
// {int i11;for (i11=0;i11<8;i11++) printf("[%.2X]",str2[i11]);printf("\n");}
while (str2[0]==0)
   { // waiting for the thread to signal it's about to finish 
   printf("%d\n",(int)str2[0]);   // "50" is shown WTF??
   sleep(1);
   }
printf("Done %d\n",(int)str2[0]);   // "50" is shown WTF??


When the main program loop started str2[0] was zero but suddenly changed to 50.
The thread is not changing it within its loop.
What gives? It works if I uncomment the line "{int i11;for (i1..." and get:
0
[00][00][00][00][00][00][00][00]
..on the screen

[toc] | [next] | [standalone]


#103795

Fromm.labanowicz@gmail.com
Date2017-02-13 05:18 -0800
Message-ID<03324b12-a3d4-447a-86eb-f23065e59795@googlegroups.com>
In reply to#103784
Hi,

There is certainly issue with synchronization (lack of it):

http://stackoverflow.com/questions/34510/what-is-a-race-condition

"the thread scheduling algorithm can swap between threads at any time"

Cheers

-- 
Maciej Labanowicz

[toc] | [prev] | [next] | [standalone]


#103804

FromTest <test@.nil.invalid.com>
Date2017-02-13 16:25 +0200
Message-ID<eof3actvintefjsnqn1o6k5g18r5b4p5qr@4ax.com>
In reply to#103795
m.labanowicz@gmail.com wrote:

>Hi,
>
>There is certainly issue with synchronization (lack of it):
>
>http://stackoverflow.com/questions/34510/what-is-a-race-condition
>
>"the thread scheduling algorithm can swap between threads at any time"
>
>Cheers

I have just one thread and one main program. While the thread is running in a
loop it is not changing any value. Only the main program changes value str1[0].
When that happen the thread is in its loop where nothing changes so there is no
race condition.

The thread function:
..
str1=alloc(50);
str1[0]=50;
while (str1[0]==50)   // the thread loop
  {
  sleep(1);  // nothing is changed in str1. The loop never exits for some reason
  }
str1[0]=2; // only here a change occurs but it never comes here
return;
}  


The main program comes here when the thread loop has been running for some time
..
str2[0]=0;  // signal thread that it should exit the loop
printf("%d\n",(int)str2[0]); // "0" is shown ie str2[0]==0
// immediately here str2[0]==50. Just what caused that?
while (str2[0]==0)   // the main program never enters this loop since
   {                 // something changed 0 back to 50
   printf("%d\n",(int)str2[0]);   // "50" is shown WTF??
   sleep(1);
   }
...

[toc] | [prev] | [next] | [standalone]


#103825

Fromm.labanowicz@gmail.com
Date2017-02-13 10:30 -0800
Message-ID<330c7242-aa78-485b-b64f-4fdfc6e2c294@googlegroups.com>
In reply to#103804
> I have just one thread and one main program.

You have to think that you have two threads:
  a) main_thread
  b) user_thread (created by main_thread)

Following scenario as example:

A) main_thread INIT:
   str1 = malloc(50);
   if (str1 == NULL) { exit(EXIT_FAILURE); }
   str2 = str1;

B) main_thread creates and starts user_thread

[main_thread]
  1: str2[0]=0;
  2: printf("%d\n",(int)str2[0]);
  3: while (str2[0]==0)
  4: {
  5:   /* Imagine that this thread at this point will sleep for 5 seconds */
  6:   /* We can simulate it with adding: */ sleep(5);
  7:   printf("%d\n",(int)str2[0]); 
  8:   sleep(1); 
  9: } 
 10: printf("Done %d\n",(int)str2[0]); 

[user_thread]
  1: /* Imagine that this thread at this point will sleep for 2 seconds */
  2: /* We can simulate it with adding: */ sleep(2);
  3: str1[0]=50;
  4: while (str1[0]==50)
  5: {
  6:   sleep(1);
  7: }
  8: /* Imagine that this thread at this point will sleep for 5 seconds */
  9: /* We can simulate it with adding: */ sleep(5);
 10: str1[0]=2;

Please analyze and tell what will be printed? :)

Note: You can imagine that such 'sleep(N) (where N is random value)' (added by OS thread scheduler) may be present at any place in the program.

-- 
ML

[toc] | [prev] | [next] | [standalone]


#103830

FromJerry Stuckle <jstucklex@attglobal.net>
Date2017-02-13 14:30 -0500
Message-ID<o7t1da$s9u$1@jstuckle.eternal-september.org>
In reply to#103825
On 2/13/2017 1:30 PM, m.labanowicz@gmail.com wrote:
>> I have just one thread and one main program.
> 
> You have to think that you have two threads:
>   a) main_thread
>   b) user_thread (created by main_thread)
> 
> Following scenario as example:
> 
> A) main_thread INIT:
>    str1 = malloc(50);
>    if (str1 == NULL) { exit(EXIT_FAILURE); }
>    str2 = str1;
> 
> B) main_thread creates and starts user_thread
> 
> [main_thread]
>   1: str2[0]=0;
>   2: printf("%d\n",(int)str2[0]);
>   3: while (str2[0]==0)
>   4: {
>   5:   /* Imagine that this thread at this point will sleep for 5 seconds */
>   6:   /* We can simulate it with adding: */ sleep(5);
>   7:   printf("%d\n",(int)str2[0]); 
>   8:   sleep(1); 
>   9: } 
>  10: printf("Done %d\n",(int)str2[0]); 
> 
> [user_thread]
>   1: /* Imagine that this thread at this point will sleep for 2 seconds */
>   2: /* We can simulate it with adding: */ sleep(2);
>   3: str1[0]=50;
>   4: while (str1[0]==50)
>   5: {
>   6:   sleep(1);
>   7: }
>   8: /* Imagine that this thread at this point will sleep for 5 seconds */
>   9: /* We can simulate it with adding: */ sleep(5);
>  10: str1[0]=2;
> 
> Please analyze and tell what will be printed? :)
> 
> Note: You can imagine that such 'sleep(N) (where N is random value)' (added by OS thread scheduler) may be present at any place in the program.
> 

You are assuming the only time main() or the thread will give up control
is when they call sleep().  That is not true; the system can take
control from virtually any application at any time - even in the middle
of a statement such as "str2 = str1" or "str2[0] = 0".

-- 
==================
Remove the "x" from my email address
Jerry Stuckle
jstucklex@attglobal.net
==================

[toc] | [prev] | [next] | [standalone]


#103798

Fromm.labanowicz@gmail.com
Date2017-02-13 05:46 -0800
Message-ID<d52fe51a-1f8d-47fe-9283-5f1c13f5a05d@googlegroups.com>
In reply to#103784
I assume that there is another case with optimizer (it depends on declaration):

> // str2 has the address of str1 in the thread, ie. (long)str1==(long)str2
> str2[0]=0;  // signal thread that it should exit the loop
> printf("%d\n",(int)str2[0]);   // "0" is shown
> // {int i11;for (i11=0;i11<8;i11++) printf("[%.2X]",str2[i11]);printf("\n");}
> while (str2[0]==0)
>    { // waiting for the thread to signal it's about to finish 
>    printf("%d\n",(int)str2[0]);   // "50" is shown WTF??
>    sleep(1);
>    }
> printf("Done %d\n",(int)str2[0]);   // "50" is shown WTF??

Loop 'while (str2[0]==0)' can be replaced by optimizer to 'while (1)'.

Solution for this is to declare str2 with 'volatile' keyword:
volatile char * str2;

The same problem is with loop in 'thread function'.

Cheers

-- 
Maciej Labanowicz

[toc] | [prev] | [next] | [standalone]


#103805

FromBen Bacarisse <ben.usenet@bsb.me.uk>
Date2017-02-13 14:30 +0000
Message-ID<87a89qtb71.fsf@bsb.me.uk>
In reply to#103798
m.labanowicz@gmail.com writes:

> I assume that there is another case with optimizer (it depends on declaration):
>
>> // str2 has the address of str1 in the thread, ie. (long)str1==(long)str2
>> str2[0]=0;  // signal thread that it should exit the loop
>> printf("%d\n",(int)str2[0]);   // "0" is shown
>> // {int i11;for (i11=0;i11<8;i11++) printf("[%.2X]",str2[i11]);printf("\n");}
>> while (str2[0]==0)
>>    { // waiting for the thread to signal it's about to finish 
>>    printf("%d\n",(int)str2[0]);   // "50" is shown WTF??
>>    sleep(1);
>>    }
>> printf("Done %d\n",(int)str2[0]);   // "50" is shown WTF??
>
> Loop 'while (str2[0]==0)' can be replaced by optimizer to 'while (1)'.
>
> Solution for this is to declare str2 with 'volatile' keyword:
> volatile char * str2;

That often works, but when it does, it sort of works by accident!

To the OP: the only reliable and portable solution is to use proper
thread synchronisation techniques.  If you have C11, it (optionally) has
them, but if not you may need to use something else like POSIX threads.

But if you are working on an embedded project, the implementation may
make enough guarantees (beyond what standard C says) so that you can
roll your own reliable shared memory accesses.

-- 
Ben.

[toc] | [prev] | [next] | [standalone]


#103849

From"Chris M. Thomasson" <invalid@invalid.invalid>
Date2017-02-13 15:13 -0800
Message-ID<o7teg7$ij4$1@dont-email.me>
In reply to#103805
On 2/13/2017 6:30 AM, Ben Bacarisse wrote:
> m.labanowicz@gmail.com writes:
>
>> I assume that there is another case with optimizer (it depends on declaration):
>>
>>> // str2 has the address of str1 in the thread, ie. (long)str1==(long)str2
>>> str2[0]=0;  // signal thread that it should exit the loop
>>> printf("%d\n",(int)str2[0]);   // "0" is shown
>>> // {int i11;for (i11=0;i11<8;i11++) printf("[%.2X]",str2[i11]);printf("\n");}
>>> while (str2[0]==0)
>>>    { // waiting for the thread to signal it's about to finish
>>>    printf("%d\n",(int)str2[0]);   // "50" is shown WTF??
>>>    sleep(1);
>>>    }
>>> printf("Done %d\n",(int)str2[0]);   // "50" is shown WTF??
>>
>> Loop 'while (str2[0]==0)' can be replaced by optimizer to 'while (1)'.
>>
>> Solution for this is to declare str2 with 'volatile' keyword:
>> volatile char * str2;
>
> That often works, but when it does, it sort of works by accident!
>
> To the OP: the only reliable and portable solution is to use proper
> thread synchronisation techniques.  If you have C11, it (optionally) has
> them, but if not you may need to use something else like POSIX threads.

Agreed. Fwiw, C11 is not supported on my systems yet. However, one can 
export their mostly likely, working C++11 threading layer in a form that 
creates a C11 layer... I wrote this half-as%ed, layer from scratch wrt 
PThreads going in that direction:

https://groups.google.com/d/topic/comp.lang.c/WPH7ed5uS4Y/discussion
(does not support 100% C11!, half-baked.)

The problem is that when you have a set of compilers that do not support 
threading in C11, well, one tends to use the C++ threading that is most 
likely supported! Damn.


> But if you are working on an embedded project, the implementation may
> make enough guarantees (beyond what standard C says) so that you can
> roll your own reliable shared memory accesses.
>

Agreed.

[toc] | [prev] | [next] | [standalone]


#103806

FromTest <test@.nil.invalid.com>
Date2017-02-13 16:36 +0200
Message-ID<ggg3acdd9s4h3p47f4488mns89opglousv@4ax.com>
In reply to#103798
m.labanowicz@gmail.com wrote:

>I assume that there is another case with optimizer (it depends on declaration):
>
>> // str2 has the address of str1 in the thread, ie. (long)str1==(long)str2
>> str2[0]=0;  // signal thread that it should exit the loop
>> printf("%d\n",(int)str2[0]);   // "0" is shown
>> // {int i11;for (i11=0;i11<8;i11++) printf("[%.2X]",str2[i11]);printf("\n");}
>> while (str2[0]==0)
>>    { // waiting for the thread to signal it's about to finish 
>>    printf("%d\n",(int)str2[0]);   // "50" is shown WTF??
>>    sleep(1);
>>    }
>> printf("Done %d\n",(int)str2[0]);   // "50" is shown WTF??
>
>Loop 'while (str2[0]==0)' can be replaced by optimizer to 'while (1)'.
>
>Solution for this is to declare str2 with 'volatile' keyword:
>volatile char * str2;
>
>The same problem is with loop in 'thread function'.
>
>Cheers


After a couple quick test runs the volative keyword appears to fix the issue. I
appears that the compiler (GCC) optimization was the culprit ..

Thanks. 

[toc] | [prev] | [next] | [standalone]


#103844

FromDavid Brown <david.brown@hesbynett.no>
Date2017-02-13 23:15 +0100
Message-ID<o7tb2c$40o$1@dont-email.me>
In reply to#103806
On 13/02/17 15:36, Test wrote:
> m.labanowicz@gmail.com wrote:
>
>> I assume that there is another case with optimizer (it depends on declaration):
>>
>>> // str2 has the address of str1 in the thread, ie. (long)str1==(long)str2
>>> str2[0]=0;  // signal thread that it should exit the loop
>>> printf("%d\n",(int)str2[0]);   // "0" is shown
>>> // {int i11;for (i11=0;i11<8;i11++) printf("[%.2X]",str2[i11]);printf("\n");}
>>> while (str2[0]==0)
>>>    { // waiting for the thread to signal it's about to finish
>>>    printf("%d\n",(int)str2[0]);   // "50" is shown WTF??
>>>    sleep(1);
>>>    }
>>> printf("Done %d\n",(int)str2[0]);   // "50" is shown WTF??
>>
>> Loop 'while (str2[0]==0)' can be replaced by optimizer to 'while (1)'.
>>
>> Solution for this is to declare str2 with 'volatile' keyword:
>> volatile char * str2;
>>
>> The same problem is with loop in 'thread function'.
>>
>> Cheers
>
>
> After a couple quick test runs the volative keyword appears to fix the issue. I
> appears that the compiler (GCC) optimization was the culprit ..
>

No, gcc optimisation was /not/ the culprit - incorrect code was the 
culprit.  If you start thinking that the optimisation is the problem and 
that using "volatile" will "disable optimisation", you are going to get 
your code badly wrong.  Adding "volatile" can make things appear to 
work, and perhaps work during your simple testing, but "volatile" alone 
is far from sufficient to make multi-threaded synchronisation work 
correctly.  You might end up with code that works while you try it, but 
fails in other circumstances, and you'll have no idea why.

You are programming on Linux here.  Linux supports a wide array of 
mutexes, semaphores, and other synchronisation systems that /work/.  You 
will have to learn to use them, and not try to invent your own with a 
bit of "volatile" here and there - you /will/ get this wrong.

[toc] | [prev] | [next] | [standalone]


#103855

FromJames Kuyper <jameskuyper@verizon.net>
Date2017-02-13 22:04 -0500
Message-ID<o7ts13$d40$1@dont-email.me>
In reply to#103844
On 02/13/2017 05:15 PM, David Brown wrote:
...
> You are programming on Linux here.  Linux supports a wide array of 
> mutexes, semaphores, and other synchronisation systems that /work/.  You 
> will have to learn to use them, and not try to invent your own with a 
> bit of "volatile" here and there - you /will/ get this wrong.

You sound like you have some idea how to do this kind of thing (which is
more than I could say about myself). I'd prefer (particularly in this
newsgroup) sticking strictly to C2011's new threading library, rather
than making any use of anything Linux-specific. Could you (or anyone
else who cares to do so) show us the right way to do something like the
OP's original code? He didn't provide a complete program, or any context
for that code, so feel free to make reasonable choices about what the
context would actually look like, without making it excessively
complicated. str1[0] seems to be being used solely for the purpose of
synchronizing execution of the two threads, and the rest of the
allocated memory is not used at all, so feel free to drop the allocated
memory entirely, and use the most appropriate method to achieve that
synchronization.

I'm not just asking this on the OP's behalf - I've little experience
with this kind of code, and none of it recent, and therefore none of it
using C2011 - so I'd like to see it for myself.

[toc] | [prev] | [next] | [standalone]


#103860

FromDavid Brown <david.brown@hesbynett.no>
Date2017-02-14 09:44 +0100
Message-ID<o7ufui$upl$1@dont-email.me>
In reply to#103855
On 14/02/17 04:04, James Kuyper wrote:
> On 02/13/2017 05:15 PM, David Brown wrote:
> ...
>> You are programming on Linux here.  Linux supports a wide array of 
>> mutexes, semaphores, and other synchronisation systems that /work/.  You 
>> will have to learn to use them, and not try to invent your own with a 
>> bit of "volatile" here and there - you /will/ get this wrong.
> 
> You sound like you have some idea how to do this kind of thing (which is
> more than I could say about myself). I'd prefer (particularly in this
> newsgroup) sticking strictly to C2011's new threading library, rather
> than making any use of anything Linux-specific. Could you (or anyone
> else who cares to do so) show us the right way to do something like the
> OP's original code? 

Not me, I'm afraid.  I know enough to know the OP is wildly up the wrong
track, and I know enough to know how big my own gaps are here - I
haven't written such code on Linux in C and would need to learn the
details myself.  (I've written Linux multi-threading code in Python, and
multi-threading code in C on small embedded systems, but not on Linux.)

To be honest, I am far from convinced that the C11 threading stuff is
useful.  The atomics can be useful (though hard to understand), but
threading is too specific to the OS in question - an abstraction like
<threads.h> is not a good match.  For Linux, you want support for
standard mutexes, fast mutexes, spinlocks, read-write locks, etc. - a
library that gives you only simple condition variables and mutexes is
not enough.  But if <threads.h> tried to cover these, it would not match
with the Windows equivalents, and be different from the vxWorks
versions, and the RTEMS locks.  And the functions that /are/ covered in
<threads.h> don't fit efficiently with the underlying functions.  If you
are using FreeRTOS on a 16-bit microcontroller, you want to specify your
timeouts in a uint16_t of milliseconds - not "struct timespec" objects
with conversions back and forth with calendar dates and nanoseconds.

> He didn't provide a complete program, or any context
> for that code, so feel free to make reasonable choices about what the
> context would actually look like, without making it excessively
> complicated. str1[0] seems to be being used solely for the purpose of
> synchronizing execution of the two threads, and the rest of the
> allocated memory is not used at all, so feel free to drop the allocated
> memory entirely, and use the most appropriate method to achieve that
> synchronization.
> 
> I'm not just asking this on the OP's behalf - I've little experience
> with this kind of code, and none of it recent, and therefore none of it
> using C2011 - so I'd like to see it for myself.
> 

[toc] | [prev] | [next] | [standalone]


#103865

FromBen Bacarisse <ben.usenet@bsb.me.uk>
Date2017-02-14 11:07 +0000
Message-ID<87lgt9rpww.fsf@bsb.me.uk>
In reply to#103860
David Brown <david.brown@hesbynett.no> writes:
<snip>

> To be honest, I am far from convinced that the C11 threading stuff is
> useful.  The atomics can be useful (though hard to understand), but
> threading is too specific to the OS in question - an abstraction like
> <threads.h> is not a good match.  For Linux, you want support for
> standard mutexes, fast mutexes, spinlocks, read-write locks, etc. - a
> library that gives you only simple condition variables and mutexes is
> not enough.

I would defer to your experience in this matter were it not for the fact
that I've heard this argument so many times over the decades.  We can't
just have loops and tests and function calls, we need computed gotos,
alternate returns and coroutines.  C's standard IO is just too crude, we
need access to the OS's record-oriented IO or what have you.

Don't get me wrong -- there will always be some cases where such an
argument is valid, and these arguments all had merit at the time due to
practical considerations, programmer experience and so on, but, in the
long run, programming has improved by offering having fewer, simpler and
more general abstractions.

The real solution is probably even higher-level abstractions at the
language level, but that's not an option for C in that C's niche will
always be a low-end of the abstraction spectrum.  So it seems at least
possible that C's threading and synchronisation mechanisms might become
the stdio.h of concurrency (in a decade or two).

The low-level mechanisms are a mess right now.  Alain Ketterlin
helpfully posted an example, but there a few things he was not sure
about.  Must the signal call be protected by the mutex, and could the
'while' used in waiting be an 'if' in this case?[1]  It all seems a bit
like the modern version of "can you jump over a declaration?".

[1] I don't want to sound curmudgeonly -- that poster was braver than I.
I considered offering an example but then thought about all the details
I'd have to check up on and how likely I would be to make a mess of it.
He clearly knows his stuff.  In fact, I think that asking when, and on
what systems, can you use 'if' like that with a condition variable would
make a good interview question!

-- 
Ben.

[toc] | [prev] | [next] | [standalone]


#103868

FromDavid Brown <david.brown@hesbynett.no>
Date2017-02-14 12:46 +0100
Message-ID<o7uqj2$vn$1@dont-email.me>
In reply to#103865
On 14/02/17 12:07, Ben Bacarisse wrote:
> David Brown <david.brown@hesbynett.no> writes:
> <snip>
> 
>> To be honest, I am far from convinced that the C11 threading stuff is
>> useful.  The atomics can be useful (though hard to understand), but
>> threading is too specific to the OS in question - an abstraction like
>> <threads.h> is not a good match.  For Linux, you want support for
>> standard mutexes, fast mutexes, spinlocks, read-write locks, etc. - a
>> library that gives you only simple condition variables and mutexes is
>> not enough.
> 
> I would defer to your experience in this matter were it not for the fact
> that I've heard this argument so many times over the decades.  We can't
> just have loops and tests and function calls, we need computed gotos,
> alternate returns and coroutines.  C's standard IO is just too crude, we
> need access to the OS's record-oriented IO or what have you.
> 

I just read Alain's post about using the mtx_ and cnd_ functions to
handle the synchronisation.  If you have semaphores, the solution is:

// Before splitting the threads
sem_t sem;
sem_init(&sem, 0, 0);

// thread 1
work1();
sem_post(&sem);

// thread 2
sem_wait(&sem);
work2();


It is much simpler and clearer, and does not need extra flag variables.

Now, the <thread.h> functions are enough to implement semaphores.  So in
that sense, they give a solid base.  But I have to wonder - who would
use them?  Why would someone use the C11 threading functions when their
OS already provides more powerful and more convenient features?  Why
would they use the new, limited functions rather than the well-known
ones with countless examples and tutorials a quick google away?

You could argue for portability - that it lets you write platform
independent multi-threaded code in C.  But you can already do that -
just use existing libraries for the purpose.  What benefits are there in
making a semaphore structure that uses the C11 thread features, as
compared to using a semaphore structure that is a wrapper around, say,
Posix and Windows semaphores?  (I can tell you without doubt that no one
will use them for things like embedded RTOS systems.)


> Don't get me wrong -- there will always be some cases where such an
> argument is valid, and these arguments all had merit at the time due to
> practical considerations, programmer experience and so on, but, in the
> long run, programming has improved by offering having fewer, simpler and
> more general abstractions.

I agree on that, in principle.  But the C11 abstractions for threading
are too few, too simple, and do not match well to real-world usage.  C11
(and C++11) threading sounds like a nice idea, but seems to me to be too
little, too late.

However, I would be quite happy to be proven wrong!

> 
> The real solution is probably even higher-level abstractions at the
> language level, but that's not an option for C in that C's niche will
> always be a low-end of the abstraction spectrum.  So it seems at least
> possible that C's threading and synchronisation mechanisms might become
> the stdio.h of concurrency (in a decade or two).
> 
> The low-level mechanisms are a mess right now.  Alain Ketterlin
> helpfully posted an example, but there a few things he was not sure
> about.  Must the signal call be protected by the mutex, and could the
> 'while' used in waiting be an 'if' in this case?[1]  It all seems a bit
> like the modern version of "can you jump over a declaration?".
> 
> [1] I don't want to sound curmudgeonly -- that poster was braver than I.
> I considered offering an example but then thought about all the details
> I'd have to check up on and how likely I would be to make a mess of it.
> He clearly knows his stuff.  In fact, I think that asking when, and on
> what systems, can you use 'if' like that with a condition variable would
> make a good interview question!
> 

[toc] | [prev] | [next] | [standalone]


#103989

FromRobert Wessel <robertwessel2@yahoo.com>
Date2017-02-16 05:12 -0600
Message-ID<152bach5uoiqh2tkkes0bp43n6vs7qrpie@4ax.com>
In reply to#103868
On Tue, 14 Feb 2017 12:46:23 +0100, David Brown
<david.brown@hesbynett.no> wrote:

>On 14/02/17 12:07, Ben Bacarisse wrote:
>> David Brown <david.brown@hesbynett.no> writes:
>> <snip>
>> 
>>> To be honest, I am far from convinced that the C11 threading stuff is
>>> useful.  The atomics can be useful (though hard to understand), but
>>> threading is too specific to the OS in question - an abstraction like
>>> <threads.h> is not a good match.  For Linux, you want support for
>>> standard mutexes, fast mutexes, spinlocks, read-write locks, etc. - a
>>> library that gives you only simple condition variables and mutexes is
>>> not enough.
>> 
>> I would defer to your experience in this matter were it not for the fact
>> that I've heard this argument so many times over the decades.  We can't
>> just have loops and tests and function calls, we need computed gotos,
>> alternate returns and coroutines.  C's standard IO is just too crude, we
>> need access to the OS's record-oriented IO or what have you.
>> 
>
>I just read Alain's post about using the mtx_ and cnd_ functions to
>handle the synchronisation.  If you have semaphores, the solution is:
>
>// Before splitting the threads
>sem_t sem;
>sem_init(&sem, 0, 0);
>
>// thread 1
>work1();
>sem_post(&sem);
>
>// thread 2
>sem_wait(&sem);
>work2();
>
>
>It is much simpler and clearer, and does not need extra flag variables.


FWIW, it was unclear to me if the OP was intending for one thread to
wait for another to complete (in which case your semaphore solution
would be exactly what the doctor ordered), or wanted one thread to
work on some process until it was signaled by the other thread (in
which case blocking on a semaphore is not what's needed).

[toc] | [prev] | [next] | [standalone]


#103994

FromDavid Brown <david.brown@hesbynett.no>
Date2017-02-16 12:44 +0100
Message-ID<o8437c$gjh$1@dont-email.me>
In reply to#103989
On 16/02/17 12:12, Robert Wessel wrote:
> On Tue, 14 Feb 2017 12:46:23 +0100, David Brown
> <david.brown@hesbynett.no> wrote:
> 
>> On 14/02/17 12:07, Ben Bacarisse wrote:
>>> David Brown <david.brown@hesbynett.no> writes:
>>> <snip>
>>>
>>>> To be honest, I am far from convinced that the C11 threading stuff is
>>>> useful.  The atomics can be useful (though hard to understand), but
>>>> threading is too specific to the OS in question - an abstraction like
>>>> <threads.h> is not a good match.  For Linux, you want support for
>>>> standard mutexes, fast mutexes, spinlocks, read-write locks, etc. - a
>>>> library that gives you only simple condition variables and mutexes is
>>>> not enough.
>>>
>>> I would defer to your experience in this matter were it not for the fact
>>> that I've heard this argument so many times over the decades.  We can't
>>> just have loops and tests and function calls, we need computed gotos,
>>> alternate returns and coroutines.  C's standard IO is just too crude, we
>>> need access to the OS's record-oriented IO or what have you.
>>>
>>
>> I just read Alain's post about using the mtx_ and cnd_ functions to
>> handle the synchronisation.  If you have semaphores, the solution is:
>>
>> // Before splitting the threads
>> sem_t sem;
>> sem_init(&sem, 0, 0);
>>
>> // thread 1
>> work1();
>> sem_post(&sem);
>>
>> // thread 2
>> sem_wait(&sem);
>> work2();
>>
>>
>> It is much simpler and clearer, and does not need extra flag variables.
> 
> 
> FWIW, it was unclear to me if the OP was intending for one thread to
> wait for another to complete (in which case your semaphore solution
> would be exactly what the doctor ordered), or wanted one thread to
> work on some process until it was signaled by the other thread (in
> which case blocking on a semaphore is not what's needed).
> 

Agreed.  I was implementing Alain's specification, rather than going
back to the OP's.

[toc] | [prev] | [next] | [standalone]


#103883

FromAlain Ketterlin <alain@universite-de-strasbourg.fr.invalid>
Date2017-02-14 15:53 +0100
Message-ID<87r330259r.fsf@universite-de-strasbourg.fr.invalid>
In reply to#103865
Ben Bacarisse <ben.usenet@bsb.me.uk> writes:

> The real solution is probably even higher-level abstractions at the
> language level, but that's not an option for C in that C's niche will
> always be a low-end of the abstraction spectrum.  So it seems at least
> possible that C's threading and synchronisation mechanisms might become
> the stdio.h of concurrency (in a decade or two).

I think threads are definitely too low-level and, well, too difficult
for regular application development. John Ousterhout has a nice set of
slides, at

http://www.cse.unsw.edu.au/~cs9242/07/lectures/10-threads.pdf

and here is a detailed analysis by Edward Lee:

http://ptolemy.eecs.berkeley.edu/publications/papers/06/problemwithThreads/

Frameworks like OpenMP or Cilk offer higher-level abstractions, but they
all have their own run-time environment, which may or may not suit one's
particular needs.

> The low-level mechanisms are a mess right now.  Alain Ketterlin
> helpfully posted an example, but there a few things he was not sure
> about.  Must the signal call be protected by the mutex, and could the
> 'while' used in waiting be an 'if' in this case?[1]  It all seems a bit
> like the modern version of "can you jump over a declaration?".

The C commitee member sitting in my cubicle confirms: there is no need
to lock the mutex to call cnd_signal() --- and this is a very bad
decision, making implementation awkward.

> [1] In fact, I think that asking when, and on what systems, can you
> use 'if' like that with a condition variable would make a good
> interview question!

How nasty :-) I would say: use a loop unless you have exactly two
threads that interact/synchronize exactly once.

-- Alain.

[toc] | [prev] | [next] | [standalone]


#103885

FromBen Bacarisse <ben.usenet@bsb.me.uk>
Date2017-02-14 15:36 +0000
Message-ID<87a89oss2h.fsf@bsb.me.uk>
In reply to#103883
Alain Ketterlin <alain@universite-de-strasbourg.fr.invalid> writes:

> Ben Bacarisse <ben.usenet@bsb.me.uk> writes:
<snip>
>> [1] In fact, I think that asking when, and on what systems, can you
>> use 'if' like that with a condition variable would make a good
>> interview question!
>
> How nasty :-) I would say: use a loop unless you have exactly two
> threads that interact/synchronize exactly once.

And then only if you know the CVs your are using a free from spurious
wake-ups -- a wait finishing when no thread has signalled the
condition.  That is sometimes done to make the implementation
efficient.  I've not checked if C makes this guarantee.  I think POSIX
does not.

-- 
Ben.

[toc] | [prev] | [next] | [standalone]


#103890

FromAlain Ketterlin <alain@universite-de-strasbourg.fr.invalid>
Date2017-02-14 17:58 +0100
Message-ID<87mvdo1zha.fsf@universite-de-strasbourg.fr.invalid>
In reply to#103885
Ben Bacarisse <ben.usenet@bsb.me.uk> writes:

> Alain Ketterlin <alain@universite-de-strasbourg.fr.invalid> writes:
>
>> Ben Bacarisse <ben.usenet@bsb.me.uk> writes:
> <snip>
>>> [1] In fact, I think that asking when, and on what systems, can you
>>> use 'if' like that with a condition variable would make a good
>>> interview question!
>>
>> How nasty :-) I would say: use a loop unless you have exactly two
>> threads that interact/synchronize exactly once.
>
> And then only if you know the CVs your are using a free from spurious
> wake-ups -- a wait finishing when no thread has signalled the
> condition.  That is sometimes done to make the implementation
> efficient.  I've not checked if C makes this guarantee.  I think POSIX
> does not.

You're right.

Actually C11 (as of N1570) does not mention the problem, but Defect
Report 480 (available at
http://www.open-std.org/jtc1/sc22/wg14/www/docs/summary.htm) implies
that spurious wakeups can happen.

POSIX (as found at http://pubs.opengroup.org/onlinepubs/9699919799/)
mentions "These functions shall not return an error code of [EINTR]."
but this does not apply to spurious wakeups, which are explicitly
mentioned ("Spurious wakeups from the pthread_cond_timedwait() or
pthread_cond_wait() functions may occur."). The informative sections
add: "It is thus recommended that a condition wait be enclosed in the
equivalent of a "while loop" that checks the predicate."

-- Alain.

[toc] | [prev] | [next] | [standalone]


#103894

FromBen Bacarisse <ben.usenet@bsb.me.uk>
Date2017-02-14 17:26 +0000
Message-ID<874lzwsmxy.fsf@bsb.me.uk>
In reply to#103890
Alain Ketterlin <alain@universite-de-strasbourg.fr.invalid> writes:

> Ben Bacarisse <ben.usenet@bsb.me.uk> writes:
>
>> Alain Ketterlin <alain@universite-de-strasbourg.fr.invalid> writes:
>>
>>> Ben Bacarisse <ben.usenet@bsb.me.uk> writes:
>> <snip>
>>>> [1] In fact, I think that asking when, and on what systems, can you
>>>> use 'if' like that with a condition variable would make a good
>>>> interview question!
>>>
>>> How nasty :-) I would say: use a loop unless you have exactly two
>>> threads that interact/synchronize exactly once.
>>
>> And then only if you know the CVs your are using a free from spurious
>> wake-ups -- a wait finishing when no thread has signalled the
>> condition.  That is sometimes done to make the implementation
>> efficient.  I've not checked if C makes this guarantee.  I think POSIX
>> does not.
>
> You're right.
>
> Actually C11 (as of N1570) does not mention the problem, but Defect
> Report 480 (available at
> http://www.open-std.org/jtc1/sc22/wg14/www/docs/summary.htm) implies
> that spurious wakeups can happen.
>
> POSIX (as found at http://pubs.opengroup.org/onlinepubs/9699919799/)
> mentions "These functions shall not return an error code of [EINTR]."
> but this does not apply to spurious wakeups, which are explicitly
> mentioned ("Spurious wakeups from the pthread_cond_timedwait() or
> pthread_cond_wait() functions may occur."). The informative sections
> add: "It is thus recommended that a condition wait be enclosed in the
> equivalent of a "while loop" that checks the predicate."

Thanks for that.  I now feel a little lazy since I should probably have
done that myself!

-- 
Ben.

[toc] | [prev] | [next] | [standalone]


Page 1 of 2  [1] 2  Next page →

Back to top | Article view | comp.lang.c


csiph-web