C语言线程基础(TinyCThread)
线程程是操作系统中进行运算调度的最小单位,它解决了同一个进程同一时刻只能占用一个核的问题,解决了同一个进程只能串行执行程序的问题。
线程是程序的载体。
由于 msvc 并没有完整的线程包,所以需要去相关网站下载线程开源的库: http://tinycthread.github.io/ 。
使用 thrd_create() 函数创建新线程。thrd_create() 函数接收三个参数,一是新定义的线程地址,二是函数指针,三是函数指针对应的函数的参数。整体意义为开辟一个新线程,运行传入的函数指针指向的函数。
#include <io_utils.h>
#include <tinycthread.h>
#include <stdio.h>
int SayHello(char *name){
printf("This is a new thread, location: [%#x], content: [%s]\n", thrd_current(), name);
return 0;
}
void main(void){
thrd_t new_thread;
int result = thrd_create(&new_thread, SayHello, "Hello World!");
if(result == thrd_success){
printf("Run in main thread: [%#x], create a new thread: [%#x]\n", thrd_current(), new_thread);
}else{
printf("Run in main thread: [%#x], failed to create a new thread\n", thrd_current());
}
}
msvc 和 mingw 编译器的运行结果如下图所示。可以发现,新开的线程并没有运行。原因是主线程运行完毕后直接关闭,子线程还未运行。
解决方法是利用 thrd_sleep() 函数使主线程 sleep 一段时间,等待子线程的运行。代码如下,thrd_sleep() 函数接收两个参数,一是 struct timespect 类型的时间,意为主线程应该等待的时间;二同样是struct timespect 类型的时间,意味着主线程实际等待的时间(实际等待时间小于应该等待时间)。
thrd_sleep(&(struct timespec){
.tv_sec = 0, .tv_nsec = 1000000}, NULL);
使用 thrd_sleep() 函数可能会带来一些问题,例如子线程运行结束,但主线程还在 sleep。可以利用 thrd_join() 函数解决子线程和主线程问题。thrd_join() 函数可以通过阻塞将子线程与主线程连接起来,当子线程执行结束时,会继续运行主线程。thrd_join() 函数接收两个参数,一是给定的子线程,二是给定子线程执行结果的返回值。
#include <io_utils.h>
#include <tinycthread.h>
int SayHello(char *name) {
PRINTLNF("Run in new thread[%#x]: Hello, %s", thrd_current(), name);
return 1;
}
int main(void) {
thrd_t new_thread;
int result = thrd_create(&new_thread, SayHello, "C lang");
if (result == thrd_success) {
PRINTLNF("Run in Main thread[%#x], created new_thread[%#x]", thrd_current(), new_thread);
} else {
PRINTLNF("Run in Main Thread[%#x], failed to create new_thread", thrd_current());
}
thrd_sleep(&(struct timespec) {
.tv_sec = 0, .tv_nsec = 100000000}, NULL);
int res;
thrd_join(new_thread, &res);
PRINTLNF("Run in Main Thread[%#x], result from thread[%#x]: %d", thrd_current(), new_thread, res);
}
可以看出创建的子线程地址主线程地址相同。这种情况与 Windows 内部实现有关,此处利用 thrd_current() 函数获取的线程地址并非对应真正的线程 id。
thrd_yield() 函数:当前线程作出声明,主动让出 CPU 资源。不过具体的情况需要 CPU 做决定,这个函数仅仅是作出声明,资源可能并没有让出。
线程在运行结束后不会主动释放资源,除非调用 thrd_join() 或 thrd_detach() 函数,线程资源才能够释放。thrd_detach() 函数类似于 fclose() 函数,传入待关闭的线程即可(thrd_detach(new_thread);)。注意, thrd_join() 或 thrd_detach() 函数两者均会关闭线程资源,是互斥关系,只能使用其一。