tylertreat / chan Goto Github PK
View Code? Open in Web Editor NEWPure C implementation of Go channels.
License: Apache License 2.0
Pure C implementation of Go channels.
License: Apache License 2.0
I written a test which compares the number of transfered messages per millisec to the number of threads. I'm using a similar test for the lock-free iqueue.
The file is located at https://github.com/je-so/testcode/blob/master/chan_speed_test.c. I'd appreciate it if you would integrate it.
See https://gist.github.com/je-so/96e5dc705d8cddb14461 where I tried to remove the blocking pipe.
I'm using chan->data to transfer the msg.
I've improved also the check for a closed channel in the unbuffered case.
The following test program produces a deadlock in case the condition variable is
implemented as FIFO (waiting readers are signalled first):
void test_chan_multi2()
{
chan_t* chan = chan_init(5);
pthread_t th[100];
for (int i = 0; i < 100; ++i) {
pthread_create(&th[i], NULL, receiver, chan);
}
sleep(1);
assert_true(chan->r_waiting >= 50, chan, "At least half of the receiver threads are waiting");
// simulate 5 high priority writing threads
pthread_mutex_lock(&chan->m_mu);
for (int i = 0; i < 5; ++i) {
assert_true(0 == queue_add(&chan->queue, "foo"), chan, "Simulate writer thread");
pthread_cond_signal(&chan->m_cond); // wakeup reader
}
// simulate 6th high priority waiting writer
assert_true(chan->queue->size == chan->queue->capacity, chan, "6th writer has to wait");
chan->w_waiting++;
// !!! simulated writer must be woken up by reader !!!
pthread_cond_wait(&chan->m_cond, &chan->m_mu);
chan->w_waiting--;
pthread_mutex_unlock(&chan->m_mu);
// wake-up other waiting reader
for (int i = 5; i < 100; ) {
if (chan_size(chan) < 5) {
++i; // one more woken up reader
chan_send(chan, "foo");
} else {
// pass cpu to reader
pthread_yield();
}
}
for (int i = 0; i < 100; ++i) {
pthread_join(th[i], NULL);
}
chan_dispose(chan);
pass();
}
The gist of the problem is:
5 waiting readers are woken up but do not run cause of the (simulated) higher priority
of writing threads. The 6th writer waits until the queue becomes not full.
Now the 5 readers run and signal the waiting writer but all 5
pthread_cond_signal(&chan->m_cond) are received by other waiting readers.
The condition variable (at least on Linux) is implemented to serve in FIFO order.
Therefore the signal is received by a waiting reader first.
Proposal:
Add two condition variables. One for readers and one for writers (not_empty vs. not_full).
Readers signal the writer condition and writers signal the reader condition.
I've encountered an issue where chan_recv
appears to be receiving sent values that were already consumed by a previous chan_recv
. This program exhibits the issue for me:
#include <stdio.h>
#include <pthread.h>
#include "chan/chan.h"
void* produce(void *_c) {
chan_t *c = (chan_t*)_c;
int code;
code = chan_send(c, (void*)(uintptr_t)1);
printf("send 1 code %d\n", code);
code = chan_send(c, (void*)(uintptr_t)2);
printf("send 2 code %d\n", code);
chan_close(c);
return NULL;
}
int main(void) {
chan_t *c = chan_init(0);
pthread_t pt;
pthread_create(&pt, NULL, produce, c);
void *v;
int code;
code = chan_recv(c, &v);
printf("recv %d code %d\n", (int)(uintptr_t)v, code);
code = chan_recv(c, &v);
printf("recv %d code %d\n", (int)(uintptr_t)v, code);
code = chan_recv(c, &v);
printf("recv %d code %d\n", (int)(uintptr_t)v, code);
pthread_join(pt, NULL);
chan_dispose(c);
return 0;
}
I would expect the output of this program to be (in some order):
recv 1 code 0
send 1 code 0
recv 2 code 0
send 2 code 0
recv 2 code -1
However, I often get the output:
recv 1 code 0
send 1 code 0
recv 2 code 0
send 2 code 0
recv 2 code 0
The third chan_recv
should never return 0
.
when search on github, I see the implementation language of the project is shell. It is better to change it to c for search
chan_select
currently only supports non-blocking selects. It should also support blocking selects, maybe by passing in a flag.
Currently, chan provides chan_send
to send data by void*
argument. But someone may want to send int/long/double/char etc.
How do you think? And I worry about someone may mistake to use chan and argument pointer. For example.
char buf[256];
while (!chan_is_closed(c)) {
if (condition) {
strcpy(buf, "doA");
} else {
strcpy(buf, "doB");
}
chan_send(c, p);
}
If the chan is possible to do buffering, the buf
will be overwritten. It need to allocation new memory for each sending. My suggestion is adding new function like below.
chan_send_string(c, buf);
chan_recv_string(c);
chan_send_int(c, 3);
chan_recv_int(c);
chan_send_double(c, 4.5);
chan_recv_double(c);
This functions allocate new memory for the types. chan_recv_int
, chan_recv_double
is possible to free the memory automatically. chan_recv_string
will be required to free memory by developers.
it would be great if there was a size param, so this library can be drop-in replaced with a compatible api for passing messages between processes.
10,000,000 mil channel possible? coz may hit linux thread creation limit?
chan_t* chan = chan_init(10000000);
Hi,
Looks like a great package! I imagine that the primary use case is go-like channels within a C program, but I'm wondering - have you actually mirrored the Go datastructure exactly? Is it possible to use CGO to embed a C program using this library inside of Go and actually send and receive on the same channel from both languages?
Thanks!
Oliver
With a certain kind of probability the following test program could produce a deadlock:
void test_chan_multi()
{
chan_t* chan = chan_init(5);
pthread_t th[100];
for (int i = 0; i < 50; ++i) {
pthread_create(&th[i], NULL, sender, chan);
}
sleep(1);
for (int i = 50; i < 100; ++i) {
pthread_create(&th[i], NULL, receiver, chan);
}
sleep(1);
for (int i = 0; i < 100; ++i) {
pthread_join(th[i], NULL);
}
chan_dispose(chan);
pass();
}
The gist of the problem is:
A waiting sender is woken up from a reader but before it could run
other readers run which do not wake up waiting senders cause
queue->size does not equal (chan->queue->capacity - 1).
Proposal:
Everytime a thread enters the critical section
let it check for waiting readers/writers (add a waiting counter)
and let it send a signal in case of waiting threads.
This solution could send more signals than necessary
but is faster than using pthread_cond_broadcast.
Hi there,
This looks like a really cool library ๐. I was wondering whether you could add it to the clib package manager? It'd make it easier for some of us to use it on our projects (like me).
If you aren't up for it I can fork it and put my local repo on the wiki, but you are the project maintainer.
Thanks! :)
(No more time to check for more errors :-))
Line 407 in b4120ab
Line 444 in b4120ab
In the implementation of chan_select
, it first checks every channel to see if it can recv/send. After that it randomly select one and do the recv/send.
What about if a channel can recv/send while checking but cannnot when really do it.
It seems the chan_select will block.
This seems to be a great feature C2x could use. Have you though about putting a proposal with this code?
I've changed queue.c (see https://gist.github.com/je-so/96e5dc705d8cddb14461#file-queue-c)
to preallocate all necessary memory.
+Pro: No more malloc/free per message transfer.
-Con: Unlimited capacity is not implemented. One could grow (realloc) the array, but the implementation would be much more complex than now.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.