mirror of
https://github.com/c3lang/c3c.git
synced 2026-02-27 12:01:16 +00:00
* add join for ThreadPool without destroying the threads * Make the main Thread block waiting for the worker threads to finish instead of buzy looping and do proper initialization and freeing of all variables. * Updated test to use `atomic_store` and take into account the maximum queue size of the threadpool. * - Add `ThreadPool` join function to wait for all threads to finish in the pool without destroying the threads. - Return of Thread/Mutex/CondVar `destroy()` is now "@maydiscard" and should be ignored. It will return void in 0.8.0. - Return of Mutex `unlock()` and `lock()` is now "@maydiscard" and should be ignored. They will return void in 0.8.0. - Return of ConditionVariable `signal()` `broadcast()` and `wait()` are now "@maydiscard". They will return void in 0.8.0. - Return of Thread `detatch()` is now "@maydiscard". It will return void in 0.8.0. - Buffered/UnbufferedChannel, and both ThreadPools have `@maydiscard` on a set of functions. They will retunr void in 0.8.0. - Pthread bindings correctly return Errno instead of CInt. - Return of Thread `join()` is now "@maydiscard". --------- Co-authored-by: Christoffer Lerno <christoffer@aegik.com>
338 lines
5.1 KiB
Plaintext
338 lines
5.1 KiB
Plaintext
module thread_test;
|
|
|
|
import std::thread::channel;
|
|
import std::thread;
|
|
import std::time;
|
|
import std::io;
|
|
|
|
fn void init_destroy_buffered() @test
|
|
{
|
|
for (usz i = 0; i < 20; i++)
|
|
{
|
|
BufferedChannel{int} c;
|
|
c.init(mem, 1)!!;
|
|
defer c.destroy();
|
|
}
|
|
}
|
|
|
|
fn void init_destroy_unbuffered() @test
|
|
{
|
|
for (usz i = 0; i < 20; i++)
|
|
{
|
|
UnbufferedChannel{int} c;
|
|
c.init(mem)!!;
|
|
defer c.destroy();
|
|
}
|
|
}
|
|
|
|
fn void push_to_buffered_channel_no_lock() @test
|
|
{
|
|
BufferedChannel{int} c;
|
|
c.init(mem, 1)!!;
|
|
defer c.destroy();
|
|
|
|
c.push(1)!!;
|
|
}
|
|
|
|
fn void push_pop_buffered_no_locks() @test
|
|
{
|
|
BufferedChannel{int} c;
|
|
c.init(mem, 1)!!;
|
|
defer c.destroy();
|
|
|
|
c.push(123)!!;
|
|
int got = c.pop()!!;
|
|
assert(got == 123);
|
|
}
|
|
|
|
fn void push_pop_unbuffered_with_locks() @test
|
|
{
|
|
UnbufferedChannel{int} c;
|
|
c.init(mem)!!;
|
|
defer c.destroy();
|
|
|
|
Thread thread;
|
|
defer thread.join();
|
|
|
|
thread.create(fn int(void* arg)
|
|
{
|
|
UnbufferedChannel{int} c = (UnbufferedChannel{int})arg;
|
|
c.push(123)!!;
|
|
c.push(321)!!;
|
|
return 0;
|
|
}, (void*)c)!!;
|
|
|
|
int got = c.pop()!!;
|
|
assert(got == 123);
|
|
got = c.pop()!!;
|
|
assert(got == 321);
|
|
}
|
|
|
|
fn void sending_to_closed_unbuffered_chan_is_forbidden() @test
|
|
{
|
|
UnbufferedChannel{int} c;
|
|
c.init(mem, )!!;
|
|
defer c.destroy();
|
|
|
|
c.close();
|
|
|
|
if (catch err = c.push(123))
|
|
{
|
|
assert(err == thread::CHANNEL_CLOSED);
|
|
return;
|
|
}
|
|
assert(false);
|
|
}
|
|
|
|
fn void sending_to_closed_buffered_chan_is_forbidden() @test
|
|
{
|
|
BufferedChannel{int} c;
|
|
c.init(mem, 1)!!;
|
|
defer c.destroy();
|
|
|
|
c.close();
|
|
|
|
if (catch err = c.push(123))
|
|
{
|
|
assert(err == thread::CHANNEL_CLOSED);
|
|
return;
|
|
}
|
|
assert(false);
|
|
}
|
|
|
|
fn void reading_from_empty_closed_unbuffered_chan_is_forbidden() @test
|
|
{
|
|
UnbufferedChannel{int} c;
|
|
c.init(mem, )!!;
|
|
defer c.destroy();
|
|
|
|
c.close();
|
|
|
|
if (catch err = c.pop())
|
|
{
|
|
assert(err == thread::CHANNEL_CLOSED);
|
|
return;
|
|
}
|
|
assert(false);
|
|
}
|
|
|
|
fn void reading_from_empty_closed_buffered_chan_is_forbidden() @test
|
|
{
|
|
BufferedChannel{int} c;
|
|
c.init(mem, 1)!!;
|
|
defer c.destroy();
|
|
|
|
c.close();
|
|
|
|
if (catch err = c.pop())
|
|
{
|
|
assert(err == thread::CHANNEL_CLOSED);
|
|
return;
|
|
}
|
|
assert(false);
|
|
}
|
|
|
|
fn void reading_from_non_empty_closed_buffered_chan_is_ok() @test
|
|
{
|
|
BufferedChannel{int} c;
|
|
c.init(mem, 3)!!;
|
|
defer c.destroy();
|
|
|
|
c.push(1)!!;
|
|
c.push(2)!!;
|
|
c.push(3)!!;
|
|
|
|
c.close();
|
|
|
|
int got = c.pop()!!;
|
|
assert(got == 1);
|
|
got = c.pop()!!;
|
|
assert(got == 2);
|
|
got = c.pop()!!;
|
|
assert(got == 3);
|
|
|
|
int? got_err = c.pop();
|
|
if (catch err = got_err)
|
|
{
|
|
assert(err == thread::CHANNEL_CLOSED);
|
|
return;
|
|
}
|
|
|
|
assert(false);
|
|
}
|
|
|
|
fn void reading_from_empty_buffered_chan_aborted_by_close() @test
|
|
{
|
|
BufferedChannel{int} c;
|
|
c.init(mem, 3)!!;
|
|
defer c.destroy();
|
|
|
|
Thread thread;
|
|
defer thread.join();
|
|
|
|
thread.create(fn int(void* arg)
|
|
{
|
|
BufferedChannel{int} c = (BufferedChannel{int})arg;
|
|
c.close();
|
|
return 0;
|
|
}, (void*)c)!!;
|
|
|
|
int? res = c.pop();
|
|
if (catch err = res)
|
|
{
|
|
assert(err == thread::CHANNEL_CLOSED);
|
|
return;
|
|
}
|
|
|
|
assert(false);
|
|
}
|
|
|
|
fn void reading_from_unbuffered_chan_aborted_by_close() @test
|
|
{
|
|
UnbufferedChannel{int} c;
|
|
c.init(mem, )!!;
|
|
defer c.destroy();
|
|
|
|
Thread thread;
|
|
defer thread.join();
|
|
|
|
thread.create(fn int(void* arg)
|
|
{
|
|
UnbufferedChannel{int} c = (UnbufferedChannel{int})arg;
|
|
c.close();
|
|
return 0;
|
|
}, (void*)c)!!;
|
|
|
|
int? res = c.pop();
|
|
if (catch err = res)
|
|
{
|
|
assert(err == thread::CHANNEL_CLOSED);
|
|
return;
|
|
}
|
|
|
|
assert(false);
|
|
}
|
|
|
|
fn void sending_to_full_buffered_chan_aborted_by_close() @test
|
|
{
|
|
BufferedChannel{int} c;
|
|
c.init(mem, 1)!!;
|
|
defer c.destroy();
|
|
|
|
c.push(1)!!;
|
|
|
|
Thread thread;
|
|
defer thread.join();
|
|
|
|
thread.create(fn int(void* arg)
|
|
{
|
|
BufferedChannel{int} c = (BufferedChannel{int})arg;
|
|
c.close();
|
|
return 0;
|
|
}, (void*)c)!!;
|
|
|
|
fault err = @catch(c.push(1));
|
|
if (err)
|
|
{
|
|
assert(err == thread::CHANNEL_CLOSED);
|
|
return;
|
|
}
|
|
|
|
assert(false);
|
|
}
|
|
|
|
fn void sending_to_unbuffered_chan_aborted_by_close() @test
|
|
{
|
|
UnbufferedChannel{int} c;
|
|
c.init(mem, )!!;
|
|
defer c.destroy();
|
|
|
|
Thread thread;
|
|
defer thread.join();
|
|
|
|
thread.create(fn int(void* arg)
|
|
{
|
|
UnbufferedChannel{int} c = (UnbufferedChannel{int})arg;
|
|
c.close();
|
|
return 0;
|
|
}, (void*)c)!!;
|
|
|
|
fault err = @catch(c.push(1));
|
|
if (err)
|
|
{
|
|
assert(err == thread::CHANNEL_CLOSED);
|
|
return;
|
|
}
|
|
|
|
assert(false);
|
|
}
|
|
|
|
fn void multiple_actions_unbuffered() @test
|
|
{
|
|
UnbufferedChannel{int} c;
|
|
c.init(mem, )!!;
|
|
defer c.destroy();
|
|
|
|
Thread thread;
|
|
defer thread.join();
|
|
|
|
thread.create(fn int(void* arg)
|
|
{
|
|
UnbufferedChannel{int} c = (UnbufferedChannel{int})arg;
|
|
for (int i = 0; i <= 100; i++)
|
|
{
|
|
c.push(i)!!;
|
|
}
|
|
return 0;
|
|
}, (void*)c)!!;
|
|
|
|
int sum;
|
|
|
|
for (int i = 0; i <= 100; i++)
|
|
{
|
|
int? res = c.pop();
|
|
if (catch err = res)
|
|
{
|
|
assert(false);
|
|
}
|
|
sum += res;
|
|
}
|
|
|
|
assert(sum == 5050);
|
|
}
|
|
|
|
fn void multiple_actions_buffered() @test
|
|
{
|
|
BufferedChannel{int} c;
|
|
c.init(mem, 10)!!;
|
|
defer c.destroy();
|
|
|
|
Thread thread;
|
|
defer thread.join();
|
|
|
|
thread.create(fn int(void* arg)
|
|
{
|
|
BufferedChannel{int} c = (BufferedChannel{int})arg;
|
|
for (int i = 0; i <= 100; i++)
|
|
{
|
|
c.push(i)!!;
|
|
}
|
|
return 0;
|
|
}, (void*)c)!!;
|
|
|
|
int sum;
|
|
|
|
for (int i = 0; i <= 100; i++)
|
|
{
|
|
int? res = c.pop();
|
|
if (catch err = res)
|
|
{
|
|
assert(false);
|
|
}
|
|
sum += res;
|
|
}
|
|
|
|
assert(sum == 5050);
|
|
}
|
|
|