Can anybody else compile and run this sucker? Thanks.
I can, but I want some input for this early stage. _____________________________________________________
#include <iostream>
#include <functional>
#include <thread>
#include <atomic>
#include <mutex>
#include <vector>
#define CT_THREAD_WORKERS_N 4
#define CT_THREAD_POLL_N 1
#define CT_THREAD_N (CT_THREAD_WORKERS_N + CT_THREAD_POLL_N)
#define CT_PER_THREAD_LOCKS_N 2
thread_local struct ct_per_thread* ct_g_per_thread = nullptr;
struct ct_shared
{
std::atomic<unsigned long> m_version;
std::mutex m_cout_mutex;
std::mutex m_threads_mutex;
std::vector<struct ct_per_thread*> m_threads;
ct_shared()
: m_version(0)
{
m_cout_mutex.lock();
std::cout << "ct_shared::ct_shared()" << std::endl;
m_cout_mutex.unlock();
}
~ct_shared()
{
m_cout_mutex.lock();
std::cout << "ct_shared::~ct_shared()" << std::endl;
m_cout_mutex.unlock();
}
};
struct ct_per_thread
{
ct_shared& m_shared;
unsigned long m_id;
std::mutex m_locks[CT_PER_THREAD_LOCKS_N];
ct_per_thread(
ct_shared& shared,
unsigned long id
): m_shared(shared),
m_id(id)
{
m_shared.m_cout_mutex.lock();
std::cout << "(" << m_id << ")-
ct_per_thread::ct_per_thread()" << std::endl;m_shared.m_cout_mutex.unlock();
}
~ct_per_thread()
{
m_shared.m_cout_mutex.lock();
std::cout << "(" << m_id << ")-
ct_per_thread::~ct_per_thread()" << std::endl;m_shared.m_cout_mutex.unlock();
// a big humm...
ct_g_per_thread = nullptr; // humm, need to ponder...
}
};
struct ct_poll_thread
{
ct_shared& m_shared;
unsigned long m_id;
ct_poll_thread(
ct_shared& shared,
unsigned long id
) : m_shared(shared),
m_id(id)
{
m_shared.m_cout_mutex.lock();
std::cout << "(" << m_id << ")-
ct_poll_thread::ct_poll_thread()" << std::endl;m_shared.m_cout_mutex.unlock();
}
~ct_poll_thread()
{
m_shared.m_cout_mutex.lock();
std::cout << "(" << m_id << ")-
ct_poll_thread::~ct_poll_thread()" << std::endl;m_shared.m_cout_mutex.unlock();
ct_g_per_thread = nullptr; // humm, need to ponder...
}
};
void
ct_worker_thread(
ct_shared& shared,
unsigned long id
) {
// get into the groove... ;^D lol.
{
shared.m_cout_mutex.lock();
std::cout << "ct_worker_thread(" << id << "), hello there!"
<< std::endl;
shared.m_cout_mutex.unlock();
}
// Humm...
// It should work fine in modern C++! :^)
{
thread_local ct_per_thread l_ct_per_thread(shared, id);
ct_g_per_thread = &l_ct_per_thread;
}
// Okay, got our per thread access via ct_g_per_thread! :^)
{
}
//Well, we have our per thread access. Use it!
{
ct_g_per_thread->m_shared.m_cout_mutex.lock();
std::cout << "ct_worker_thread(" << id << "), goodbye
everybody from here! ;^o" << std::endl;
ct_g_per_thread->m_shared.m_cout_mutex.unlock();
}
}
void
ct_poll_thread(
ct_shared& shared,
unsigned long id
) {
// get into the groove... ;^D lol.
{
shared.m_cout_mutex.lock();
std::cout << "\nct_poll_thread(" << id << "), hello there!"
<< std::endl;
shared.m_cout_mutex.unlock();
}
// Humm...
// It should work fine in modern C++! :^)
{
thread_local ct_per_thread l_ct_per_thread(shared, id);
ct_g_per_thread = &l_ct_per_thread;
}
// Okay, got our per thread access via ct_g_per_thread! :^)
{
for (unsigned long i = 0; i < 42; ++i)
{
shared.m_cout_mutex.lock();
std::cout << "\nct_poll_thread(" << id << "), iterate:"
<< i << std::endl;
shared.m_cout_mutex.unlock();
}
}
//Well, we have our per thread access. Use it!
{
ct_g_per_thread->m_shared.m_cout_mutex.lock();
std::cout << "ct_poll_thread(" << id << "), goodbye everybody from here! ;^o\n" << std::endl;
ct_g_per_thread->m_shared.m_cout_mutex.unlock();
}
}
int
main()
{
std::cout << "ct_proxy_collector testing 123...\n";
std::cout << "_________________________________\n\n" << std::endl;
{
ct_shared shared;
{
std::thread threads[CT_THREAD_N];
std::cout << "Launching threads and processing...\n";
std::cout << "____________________\n" << std::endl;
{
{
// Create worker threads...
for (unsigned long i = 0; i < CT_THREAD_WORKERS_N;
++i)
{
threads[i] = std::thread(ct_worker_thread,
std::ref(shared), i);
}
// Create poll threads...
for (unsigned long i = CT_THREAD_WORKERS_N; i <
CT_THREAD_N; ++i)
{
threads[i] = std::thread(ct_poll_thread,
std::ref(shared), i);
}
}
// Wait for them...
for (unsigned long i = 0; i < CT_THREAD_N; ++i)
{
threads[i].join();
}
}
std::cout << "____________________\n" << std::endl;
}
std::cout << "Complete!\n";
std::cout << "____________________\n" << std::endl;
}
std::cout << "\nFin!\n____________________\n" << std::endl;
return 0;
}
_____________________________________________________
On 30.10.2024 07:38, Chris M. Thomasson wrote:[...]
Can anybody else compile and run this sucker? Thanks.
I can, but I want some input for this early stage.
_____________________________________________________
_____________________________________________________
Seems to compile and run fine with VS2022 on x64:
ct_proxy_collector testing 123...[...]
_________________________________
Complete!
____________________
ct_shared::~ct_shared()
Fin!
____________________
On 10/30/2024 9:09 AM, Paavo Helde wrote:[...]
On 30.10.2024 07:38, Chris M. Thomasson wrote:
This base will help me be able to test all sort of interesting proxy algorithms.
This base will help me be able to test all sort of interesting proxy algorithms.
On 10/30/24 15:30, Chris M. Thomasson wrote:
This is a far as I got coming up with a proxy api
This base will help me be able to test all sort of interesting proxy
algorithms.
template<typename T>
concept BasicLockable = requires(T a)
{
{ a.lock() } -> std::same_as<void>;
{ a.unlock() } -> std::same_as<void>;
};
/**
* @tparm T proxy collector type
* @tparm B base object type for managed objects
*/
template<typename T, typename B>
concept ProxyType = requires(T proxy, B * obj)
{
BasicLockable<T>;
std::has_virtual_destructor<B>::value; // base object
must have virtual destructor
{ proxy.unregister() } -> std::same_as<void>; // unregister
thread
{ proxy.retire(obj) } -> std::same_as<bool>; // true if
reclaim thread needs notification
{ proxy.retire_is_lockfree() } -> std::same_as<bool>;
{ proxy.retire_is_synchronous() } -> std::same_as<bool>;
{ proxy.try_reclaim() } -> std::same_as<bool>; // false if no
more pending retires
};
I did smrproxy and shared lock. I didn't do arcproxy or
any others.
try_reclaim is so you can run your own reclaim thread with
retire and try_reclaim results to you could do notifies if
necesary.
retire_is_syncrhonous means no deferred retire so no
try_reclaim is necessary. Kind of moot. If I go
with rust I'll use rust traits.
On 10/30/24 15:30, Chris M. Thomasson wrote:
This is a far as I got coming up with a proxy api
This base will help me be able to test all sort of interesting proxy
algorithms.
template<typename T>
concept BasicLockable = requires(T a)
{
{ a.lock() } -> std::same_as<void>;
{ a.unlock() } -> std::same_as<void>;
};
/**
* @tparm T proxy collector type
* @tparm B base object type for managed objects
*/
template<typename T, typename B>
concept ProxyType = requires(T proxy, B * obj)
{
BasicLockable<T>;
std::has_virtual_destructor<B>::value; // base object
must have virtual destructor
{ proxy.unregister() } -> std::same_as<void>; // unregister
thread
{ proxy.retire(obj) } -> std::same_as<bool>; // true if
reclaim thread needs notification
{ proxy.retire_is_lockfree() } -> std::same_as<bool>;
{ proxy.retire_is_synchronous() } -> std::same_as<bool>;
{ proxy.try_reclaim() } -> std::same_as<bool>; // false if no
more pending retires
};
I did smrproxy and shared lock. I didn't do arcproxy or
any others.
try_reclaim is so you can run your own reclaim thread with
retire and try_reclaim results to you could do notifies if
necesary.
retire_is_syncrhonous means no deferred retire so no
try_reclaim is necessary. Kind of moot. If I go
with rust I'll use rust traits.
Can anybody else compile and run this sucker? Thanks.
I can, but I want some input for this early stage. _____________________________________________________
<snip>
_____________________________________________________
On 10/30/2024 1:25 PM, jseigh wrote:
On 10/30/24 15:30, Chris M. Thomasson wrote:
This is a far as I got coming up with a proxy api
This base will help me be able to test all sort of interesting proxy
algorithms.
template<typename T>
concept BasicLockable = requires(T a)
{
{ a.lock() } -> std::same_as<void>;
{ a.unlock() } -> std::same_as<void>;
Humm... For some reason it might be helpful for lock to return a epoch,
or proxy_state thing or some sort of state. Then pass it into unlock.
proxy_state lock();
void unlock(proxy_state const&);
Fwiw, I do this wrt my acquire and release functions, akin to your lock
and unlock functions:
collector& acquire()
{
[...]
}
void release(collector& c)
{
[...]
}
Humm...
On 10/30/24 17:06, Chris M. Thomasson wrote:
On 10/30/2024 1:25 PM, jseigh wrote:I use lock/unlock because RCU uses the BasicLocking requirement so std::scoped_lock can be used. c++ wasn't going to provide some
On 10/30/24 15:30, Chris M. Thomasson wrote:
This is a far as I got coming up with a proxy api
This base will help me be able to test all sort of interesting proxy
algorithms.
template<typename T>
concept BasicLockable = requires(T a)
{
{ a.lock() } -> std::same_as<void>;
{ a.unlock() } -> std::same_as<void>;
Humm... For some reason it might be helpful for lock to return a
epoch, or proxy_state thing or some sort of state. Then pass it into
unlock.
proxy_state lock();
void unlock(proxy_state const&);
Fwiw, I do this wrt my acquire and release functions, akin to your
lock and unlock functions:
collector& acquire()
{
[...]
}
void release(collector& c)
{
[...]
}
Humm...
king of scoped block for RCU like Java's synchronized block.
C++ really really likes RAII a lot even though it logically
creates a local variable whereas synchronized would not.
Can anybody else compile and run this sucker? Thanks.
I can, but I want some input for this early stage.
"Chris M. Thomasson" <chris.m.thomasson.1@gmail.com> writes:...
Just curious, are line breaks inside strings OK in some environment? Or
is that a language version thing? Here g++ 10.2.1 doesn't like this sort
of thing:
std::cout << "ct_worker_thread(" << id << "), goodbye
everybody from here! ;^o" << std::endl;
On 10/31/24 05:47, Anssi Saari wrote:
"Chris M. Thomasson" <chris.m.thomasson.1@gmail.com> writes:...
Just curious, are line breaks inside strings OK in some environment? Or
is that a language version thing? Here g++ 10.2.1 doesn't like this sort
of thing:
std::cout << "ct_worker_thread(" << id << "), goodbye
everybody from here! ;^o" << std::endl;
You're attempting to create a string literal, but the syntax for string >literals does not allow them to contain newline characters.
"Chris M. Thomasson" <chris.m.thomasson.1@gmail.com> writes:
Can anybody else compile and run this sucker? Thanks.
I can, but I want some input for this early stage.
Just curious, are line breaks inside strings OK in some environment? Or
is that a language version thing? Here g++ 10.2.1 doesn't like this sort
of thing:
std::cout << "ct_worker_thread(" << id << "), goodbye
everybody from here! ;^o" << std::endl;
Tried newer g++ and clang++ too but no. Joining those two lines, no
problem. I don't think I wrapped that line either. And there's another
one too.
James Kuyper <jameskuyper@alumni.caltech.edu> writes:
On 10/31/24 05:47, Anssi Saari wrote:
"Chris M. Thomasson" <chris.m.thomasson.1@gmail.com> writes:...
Just curious, are line breaks inside strings OK in some environment? Or
is that a language version thing? Here g++ 10.2.1 doesn't like this sort >>> of thing:
std::cout << "ct_worker_thread(" << id << "), goodbye
everybody from here! ;^o" << std::endl;
You're attempting to create a string literal, but the syntax for string
literals does not allow them to contain newline characters.
Unless they're escaped.
const char * string = "blah blah blah \
blah blah blah";
James Kuyper <jameskuyper@alumni.caltech.edu> writes:
On 10/31/24 05:47, Anssi Saari wrote:
"Chris M. Thomasson" <chris.m.thomasson.1@gmail.com> writes:...
Just curious, are line breaks inside strings OK in some environment? Or
is that a language version thing? Here g++ 10.2.1 doesn't like this sort >>> of thing:
std::cout << "ct_worker_thread(" << id << "), goodbye
everybody from here! ;^o" << std::endl;
You're attempting to create a string literal, but the syntax for string
literals does not allow them to contain newline characters.
Unless they're escaped.
const char * string = "blah blah blah \
blah blah blah";
On 31.10.2024 20:43, Scott Lurndal wrote:
Unless they're escaped.
const char * string = "blah blah blah \
blah blah blah";
That's C style, and the result would not contain a line break. In C++ we
have "raw" string literals which can contain embedded linebreaks.
const char * string = R"__(blah blah blah
blah blah blah)__";
This comes pretty handy sometimes.
On Fri, 1 Nov 2024 23:39:36 +0200
Paavo Helde <eesnimi@osa.pri.ee> gabbled:
On 31.10.2024 20:43, Scott Lurndal wrote:
Unless they're escaped.
const char * string = "blah blah blah \
blah blah blah";
That's C style, and the result would not contain a line break. In C++ we
Probably why K&R invented \n in the first place. Not sure why anyone would want to embed a raw linebreak in code.
have "raw" string literals which can contain embedded linebreaks.
const char * string = R"__(blah blah blah
blah blah blah)__";
This comes pretty handy sometimes.
Hmm.
fenris$ cat t.cc
#include <stdio.h>
int main()
{
const char *s = R"hello
world";
puts(s);
}
fenris$ c++ -std=c++20 t.cc
t.cc:5:25: error: invalid character '
' character in raw string delimiter; use PREFIX( )PREFIX to delimit raw string
5 | const char *s = R"hello
| ^ t.cc:5:18: error: expected expression
5 | const char *s = R"hello
| ^
2 errors generated.
fenris$ c++ -v
Apple clang version 16.0.0 (clang-1600.0.26.3)
Target: x86_64-apple-darwin24.0.0
Thread model: posix
InstalledDir: /Library/Developer/CommandLineTools/usr/bin
Tried PREFIX, it didn't like that either. Oh well, not something I'll lose sleep over.
On Fri, 1 Nov 2024 23:39:36 +0200
Paavo Helde <eesnimi@osa.pri.ee> gabbled:
On 31.10.2024 20:43, Scott Lurndal wrote:
Unless they're escaped.
const char * string = "blah blah blah \
blah blah blah";
That's C style, and the result would not contain a line break. In C++ we
Probably why K&R invented \n in the first place. Not sure why anyone would >want to embed a raw linebreak in code.
On 02.11.2024 11:51, Muttley@dastardlyhq.com wrote:
Tried PREFIX, it didn't like that either. Oh well, not something I'll lose >> sleep over.
You are missing the __( and )__ parts. Here:
#include <stdio.h>
int main() {
const char* s = R"__(hello
world)__";
puts(s);
}
Example of real usage (depending on your newsreader, long lines may
appear broken):
Yes, I could have composed it in a much harder way than by copy-paste
from a debugger window, but why would I bother?
On 10/29/2024 11:38 PM, Chris M. Thomasson wrote:[...]
Can anybody else compile and run this sucker? Thanks.
I can, but I want some input for this early stage.
_____________________________________________________
<snip>
_____________________________________________________
Compiled clean with -Wall -Werror using:
g++ (GCC) 14.2.1 20240912 (Red Hat 14.2.1-3).
Output is:
=====================================================
ct_poll_thread(4), iterate:41
ct_poll_thread(4), goodbye everybody from here! ;^o
(4)->ct_per_thread::~ct_per_thread()
____________________
Complete!
____________________
ct_shared::~ct_shared()
Fin!
____________________
=====================================================
On Sat, 2 Nov 2024 17:16:26 +0200
Paavo Helde <eesnimi@osa.pri.ee> gabbled:
On 02.11.2024 11:51, Muttley@dastardlyhq.com wrote:
Tried PREFIX, it didn't like that either. Oh well, not something I'll
lose
sleep over.
You are missing the __( and )__ parts. Here:
#include <stdio.h>
int main() {
const char* s = R"__(hello
world)__";
puts(s);
}
Jesus christ, how much more contorted nonsense syntax can they come up
with.
Now there's compiler semantics inside a raw string?? FFS, this language is becoming a joke.
Example of real usage (depending on your newsreader, long lines may
appear broken):
Rather contrived given it would be simple just to put \n on the end of each line. I still don't see the point.
Yes, I could have composed it in a much harder way than by copy-paste
from a debugger window, but why would I bother?
Why would you cut and paste this stuff anyway into code?
On 02.11.2024 18:48, Muttley@dastardlyhq.com wrote:
On Sat, 2 Nov 2024 17:16:26 +0200
Paavo Helde <eesnimi@osa.pri.ee> gabbled:
On 02.11.2024 11:51, Muttley@dastardlyhq.com wrote:
Tried PREFIX, it didn't like that either. Oh well, not something I'll >>>> lose
sleep over.
You are missing the __( and )__ parts. Here:
#include <stdio.h>
int main() {
const char* s = R"__(hello
world)__";
puts(s);
}
Jesus christ, how much more contorted nonsense syntax can they come up
with.
Now there's compiler semantics inside a raw string?? FFS, this language is >> becoming a joke.
If you haven't figured this out, multicharacter (and potentially
variable) delimiters are needed for unambiguous matching of the end of
the string. This dates back to shell heredoc, and probably older, so not >exactly a new invention.
Why would you cut and paste this stuff anyway into code?
This is just a random example of some test data for testing the app in >nightly builds. I could have put it in a separate file or elsewhere, but
Posting code in the newsreader can cause this: Sorry about that. Here
are some screenshots of my current code:
https://i.ibb.co/YtdKLfz/image.png
https://i.ibb.co/DDnrdqL/image.png
Not ready to be posted to github at this early stage.
"Chris M. Thomasson" <chris.m.thomasson.1@gmail.com> writes:
Posting code in the newsreader can cause this: Sorry about that. Here
are some screenshots of my current code:
https://i.ibb.co/YtdKLfz/image.png
https://i.ibb.co/DDnrdqL/image.png
OK, I thought you'd handle it. As in, as someone who posts code you
would turn off line wrapping when posting code. But I guess Usenet
doesn't integrate that well to modern code editors.
Given that my newsreader (Thunderbird 128.4.0esr) shows the lines in
the original post from Chris correctly, I would not be so quick in
blaming him or his tools.
But in general it's true that broken lines in usenet postings are
still a frequent problem. Just fix the lines by yourself as needed, if
the issues have not been solved in 45 years there is little hope they
will be solved now.
Paavo Helde <eesnimi@osa.pri.ee> writes:
Given that my newsreader (Thunderbird 128.4.0esr) shows the lines in
the original post from Chris correctly, I would not be so quick in
blaming him or his tools.
You're right, it's my tool that's wrong. Or, well... With the MIME
directive format=flowed there's only a hint that trailing whitespace on
one line means the next line can be joined. Readers are still free to reformat such text as they please and what fits on a particular screen
or window. At least that's how I understand RFC2646.
Gnus here followed that so that it used matching indent when joining so code looked like this:
std::cout << "ct_poll_thread(" << id << "), goodbye
everybody from here! ;^o\n" << std::endl;
This isn't valid C++ and the raw article isn't either.
I guess if you compiled the code without having to edit it you
copy-pasted it from TB?
But in general it's true that broken lines in usenet postings are
still a frequent problem. Just fix the lines by yourself as needed, if
the issues have not been solved in 45 years there is little hope they
will be solved now.
I think this has been solved in many ways, people just aren't aware
and/or not using the solutions.
On 10/30/24 17:06, Chris M. Thomasson wrote:
On 10/30/2024 1:25 PM, jseigh wrote:I use lock/unlock because RCU uses the BasicLocking requirement so std::scoped_lock can be used. c++ wasn't going to provide some
On 10/30/24 15:30, Chris M. Thomasson wrote:
This is a far as I got coming up with a proxy api
This base will help me be able to test all sort of interesting proxy
algorithms.
template<typename T>
concept BasicLockable = requires(T a)
{
{ a.lock() } -> std::same_as<void>;
{ a.unlock() } -> std::same_as<void>;
Humm... For some reason it might be helpful for lock to return a
epoch, or proxy_state thing or some sort of state. Then pass it into
unlock.
proxy_state lock();
void unlock(proxy_state const&);
Fwiw, I do this wrt my acquire and release functions, akin to your
lock and unlock functions:
collector& acquire()
{
[...]
}
void release(collector& c)
{
[...]
}
Humm...
king of scoped block for RCU like Java's synchronized block.
C++ really really likes RAII a lot even though it logically
creates a local variable whereas synchronized would not.
On 10/30/24 15:30, Chris M. Thomasson wrote:
This is a far as I got coming up with a proxy api
This base will help me be able to test all sort of interesting proxy
algorithms.
template<typename T>
concept BasicLockable = requires(T a)
{
{ a.lock() } -> std::same_as<void>;
{ a.unlock() } -> std::same_as<void>;
};
/**
* @tparm T proxy collector type
* @tparm B base object type for managed objects
*/
template<typename T, typename B>
concept ProxyType = requires(T proxy, B * obj)
{
BasicLockable<T>;
std::has_virtual_destructor<B>::value; // base object
must have virtual destructor
{ proxy.unregister() } -> std::same_as<void>; // unregister
thread
{ proxy.retire(obj) } -> std::same_as<bool>; // true if
reclaim thread needs notification
{ proxy.retire_is_lockfree() } -> std::same_as<bool>;
{ proxy.retire_is_synchronous() } -> std::same_as<bool>;
{ proxy.try_reclaim() } -> std::same_as<bool>; // false if no
more pending retires
};
I did smrproxy and shared lock. I didn't do arcproxy or
any others.
try_reclaim is so you can run your own reclaim thread with
retire and try_reclaim results to you could do notifies if
necesary.
retire_is_syncrhonous means no deferred retire so no
try_reclaim is necessary. Kind of moot. If I go
with rust I'll use rust traits.
On 10/30/24 16:25, jseigh wrote:
On 10/30/24 15:30, Chris M. Thomasson wrote:
This is a far as I got coming up with a proxy api
This base will help me be able to test all sort of interesting proxy
algorithms.
template<typename T>
concept BasicLockable = requires(T a)
{
{ a.lock() } -> std::same_as<void>;
{ a.unlock() } -> std::same_as<void>;
};
/**
* @tparm T proxy collector type
* @tparm B base object type for managed objects
*/
template<typename T, typename B>
concept ProxyType = requires(T proxy, B * obj)
{
BasicLockable<T>;
std::has_virtual_destructor<B>::value; // base
object must have virtual destructor
{ proxy.unregister() } -> std::same_as<void>; // unregister
thread
{ proxy.retire(obj) } -> std::same_as<bool>; // true if
reclaim thread needs notification
{ proxy.retire_is_lockfree() } -> std::same_as<bool>;
{ proxy.retire_is_synchronous() } -> std::same_as<bool>;
{ proxy.try_reclaim() } -> std::same_as<bool>; // false if
no more pending retires
};
I did smrproxy and shared lock. I didn't do arcproxy or
any others.
try_reclaim is so you can run your own reclaim thread with
retire and try_reclaim results to you could do notifies if
necesary.
retire_is_syncrhonous means no deferred retire so no
try_reclaim is necessary. Kind of moot. If I go
with rust I'll use rust traits.
I have arcproxy mostly ported to c++ so that's 4
different proxy implementations. I may rethink
making the proxy itself BasicLockable. Using
thread_local tends to turn everything into a
singleton unless one resorts to using some hack.
Progress would be quicker but c++ templates
turn IDEs back into dumb text editors.
On 11/13/2024 10:43 AM, jseigh wrote:
I have arcproxy mostly ported to c++ so that's 4
different proxy implementations. I may rethink
making the proxy itself BasicLockable. Using
thread_local tends to turn everything into a
singleton unless one resorts to using some hack.
Humm... I have been experimenting with thread_local and it's working
fine for my testing needs. I can get per-thread dtors, which is nice. At least they are working okay now. Back when I was first experimenting
(years ago) with them, some of the dtors were not being called.
Registering per-thread data with the polling thread is the tricky part. Lifetime issues. But, I have that solved for my testing needs.
On 11/13/24 16:04, Chris M. Thomasson wrote:
On 11/13/2024 10:43 AM, jseigh wrote:
I have arcproxy mostly ported to c++ so that's 4
different proxy implementations. I may rethink
making the proxy itself BasicLockable. Using
thread_local tends to turn everything into a
singleton unless one resorts to using some hack.
Humm... I have been experimenting with thread_local and it's working
fine for my testing needs. I can get per-thread dtors, which is nice.
At least they are working okay now. Back when I was first
experimenting (years ago) with them, some of the dtors were not being
called.
Registering per-thread data with the polling thread is the tricky
part. Lifetime issues. But, I have that solved for my testing needs.
It's not a question of making it work. It's awkward to use.
If you are trying to dynamically create them, c++'s insistence
on doing everything at compile time makes it more work than
it has to be.
On 11/13/2024 1:26 PM, jseigh wrote:
On 11/13/24 16:04, Chris M. Thomasson wrote:
On 11/13/2024 10:43 AM, jseigh wrote:
I have arcproxy mostly ported to c++ so that's 4
different proxy implementations. I may rethink
making the proxy itself BasicLockable. Using
thread_local tends to turn everything into a
singleton unless one resorts to using some hack.
Humm... I have been experimenting with thread_local and it's working
fine for my testing needs. I can get per-thread dtors, which is nice.
At least they are working okay now. Back when I was first
experimenting (years ago) with them, some of the dtors were not being
called.
Registering per-thread data with the polling thread is the tricky
part. Lifetime issues. But, I have that solved for my testing needs.
It's not a question of making it work. It's awkward to use.
If you are trying to dynamically create them, c++'s insistence
on doing everything at compile time makes it more work than
it has to be.
Hard to disagree with that! Humm...
Is this a massive hack?
thread_local struct ct_per_thread* ct_g_per_thread = nullptr;
On 11/13/24 16:38, Chris M. Thomasson wrote:
On 11/13/2024 1:26 PM, jseigh wrote:
On 11/13/24 16:04, Chris M. Thomasson wrote:
On 11/13/2024 10:43 AM, jseigh wrote:
I have arcproxy mostly ported to c++ so that's 4
different proxy implementations. I may rethink
making the proxy itself BasicLockable. Using
thread_local tends to turn everything into a
singleton unless one resorts to using some hack.
Humm... I have been experimenting with thread_local and it's working
fine for my testing needs. I can get per-thread dtors, which is
nice. At least they are working okay now. Back when I was first
experimenting (years ago) with them, some of the dtors were not
being called.
Registering per-thread data with the polling thread is the tricky
part. Lifetime issues. But, I have that solved for my testing needs.
It's not a question of making it work. It's awkward to use.
If you are trying to dynamically create them, c++'s insistence
on doing everything at compile time makes it more work than
it has to be.
Hard to disagree with that! Humm...
Is this a massive hack?
No, fairly simple but potentially unsafe. Very unsafe :)
...
thread_local struct ct_per_thread* ct_g_per_thread = nullptr;
I had considered the preallocated array but you have to guess
what is a reasonable size, have logic for reusing ids/keys,
and if you run out of slots, you have a runtime error the
apps have to deal with. Basically your proxy ctor would have
to throw an exception if no slots were available. Same as
if pthread_key_create returned an error.
On 11/14/2024 6:06 AM, jseigh wrote:
I had considered the preallocated array but you have to guess
what is a reasonable size, have logic for reusing ids/keys,
and if you run out of slots, you have a runtime error the
apps have to deal with. Basically your proxy ctor would have
to throw an exception if no slots were available. Same as
if pthread_key_create returned an error.
Need to ponder on this. So, are you saying that no calls to pthread_key_delete would be made and eventually it would run out of
slots? PTHREADS_KEY_MAX? Need to think here.
Although, iirc one key can handle multiple threads via:
pthread_setspecific
pthread_getspecific
So, my scheme would require two of them for the lifetime of the program?
On 11/14/24 17:08, Chris M. Thomasson wrote:
On 11/14/2024 6:06 AM, jseigh wrote:
I had considered the preallocated array but you have to guess
what is a reasonable size, have logic for reusing ids/keys,
and if you run out of slots, you have a runtime error the
apps have to deal with. Basically your proxy ctor would have
to throw an exception if no slots were available. Same as
if pthread_key_create returned an error.
Need to ponder on this. So, are you saying that no calls to
pthread_key_delete would be made and eventually it would run out of
slots? PTHREADS_KEY_MAX? Need to think here.
The thread specific storage segment is fixed in size, the
sum of all the thread_local declares. So pthreads has to
reserve how many slots it thinks it needs.
Although, iirc one key can handle multiple threads via:
pthread_setspecific
pthread_getspecific
So, my scheme would require two of them for the lifetime of the program?
On 11/13/2024 10:43 AM, jseigh wrote:[...]
Progress would be quicker but c++ templates
turn IDEs back into dumb text editors.
lol.
On 11/13/24 16:38, Chris M. Thomasson wrote:
Is this a massive hack?
No, fairly simple but potentially unsafe. Very unsafe :)
On 11/14/24 09:06, jseigh wrote:
On 11/13/24 16:38, Chris M. Thomasson wrote:
Is this a massive hack?
No, fairly simple but potentially unsafe. Very unsafe :)
So if you want to program dangerously.
Basically your class declares a thread_local which
would normally make it a singleton class effectively.
You can create other non singleton instances by
having a constructor which takes a locally declared
thread_local passed in a a ctor argument. You
then take the difference between that and the
"singleton" thread_local and use that as an array
index to access the appropriate thread_local.
So "dynamic" thread_locals without having to
guess at how many preallocated thread locals
to create
On 11/14/24 09:06, jseigh wrote:
On 11/13/24 16:38, Chris M. Thomasson wrote:
Is this a massive hack?
No, fairly simple but potentially unsafe. Very unsafe :)
So if you want to program dangerously.
Basically your class declares a thread_local which
would normally make it a singleton class effectively.
You can create other non singleton instances by
having a constructor which takes a locally declared
thread_local passed in a a ctor argument. You
then take the difference between that and the
"singleton" thread_local and use that as an array
index to access the appropriate thread_local.
So "dynamic" thread_locals without having to
guess at how many preallocated thread locals
to create
thread_local int base; // used for singleton instance
thread_local int other; // used for some other instance
int ndx = &base - &other; // stored in instance to access instance
// tls
(&base)[ndx] ... // access the instance tls
Don't store or precalculate &base. It will be different for every
thread. There's no portable way to validate an address to see if
it is a tls address.
On 11/14/24 09:06, jseigh wrote:
On 11/13/24 16:38, Chris M. Thomasson wrote:
Is this a massive hack?
No, fairly simple but potentially unsafe. Very unsafe :)
So if you want to program dangerously.
Basically your class declares a thread_local which
would normally make it a singleton class effectively.
You can create other non singleton instances by
having a constructor which takes a locally declared
thread_local passed in a a ctor argument. You
then take the difference between that and the
"singleton" thread_local and use that as an array
index to access the appropriate thread_local.
So "dynamic" thread_locals without having to
guess at how many preallocated thread locals
to create
thread_local int base; // used for singleton instance
thread_local int other; // used for some other instance
int ndx = &base - &other; // stored in instance to access instance
// tls
(&base)[ndx] ... // access the instance tls
Sysop: | DaiTengu |
---|---|
Location: | Appleton, WI |
Users: | 991 |
Nodes: | 10 (1 / 9) |
Uptime: | 131:00:41 |
Calls: | 12,960 |
Calls today: | 2 |
Files: | 186,574 |
Messages: | 3,266,055 |