线程轮询阻塞,由系统调度唤醒,实时性不高。
线程阻塞的方式好多,不过根本原因是调用能引起调度的函数即可,其他的工作就让系统调度来完成。
readThread{ while(TRUE){ sleep(3); //数据处理 } }
最简单的就是使用sleep函数让线程进入休眠。等休眠结束后,线程由“阻塞状态”进入“就绪状态”,期间就需要系统根据不同线程间的nice值来评判运行的优先级。显然这种方式的实时性不高,而且还可能被系统中断打断的可能。不过对于我们而言,这种状态已经足够了。因为现在的系统都是微秒级别,基本差别不到差别。而且对于使用这种方式的用户,也不需要很高的实时性要求。足够我们使用了。
再次说到,内核空间的用法跟用户空间很相似。这种使用方法,在内核也有相应的办法实现的,除了像上面的使用方法外,内核还可以借助schedule的系统调度来完成,这种方式直接使用系统调度,更为简洁。而且对于开一个调度和开一线程,对于内核而言,原理性都是一样的。所以在内核里面的做法,是建议使用schedule的方式,而且有需要的话,还可以使用schedule_work_on和schedule_delayed_owrk_on来指定执行的CPU,资源由我们自动分配。
首先说明一下,在Linux编写多线程程序需要包含头文件pthread.h。也就是说你在任何采用多线程设计的程序中都会看到类似这样的代码: #include <pthread.h> 当然,进包含一个头文件是不能搞定线程的,还需要连接libpthread.so这个库,因此在程序连接阶段应该有类似这样的指令: gcc program.o -o program -lpthread
头文件: <pthread.h> 原型: pthread_t pthread_self(); 返回值: 返回调用线程的线程ID. 二、线程创建 在执行中创建一个线程, 可以为该线程分配它需要做的工作(线程执行函数), 该线程共享进程的资源. 创建线程的函数pthread_create() 头文件: <pthread.h> 原型: int pthread_create(pthread_t *restrict tidp, const pthread_attr_t *restrict attr, void *(start_rtn)(void), void *restrict arg); 返回值: 成功则返回0, 否则返回错误编号. 参数: tidp: 指向新创建线程ID的变量, 作为函数的输出. attr: 用于定制各种不同的线程属性, NULL为默认属性(见下). start_rtn: 函数指针, 为线程开始执行的函数名.该函数可以返回一个void *类型的返回值,而这个返回值也可以是其他类型,并由 pthread_join()获取 arg: 函数的唯一无类型(void)指针参数, 如要传多个参数, 可以用结构封装. linux下多线程程序的编译方法: 因为pthread的库不是linux系统的库,所以在进行编译的时候要加上 -lpthread # gcc filename -lpthread //默认情况下gcc使用c库,要使用额外的库要这样选择使用的库
线程的合并与分离 我们首先要明确的一个问题就是什么是线程的合并。从前面的叙述中读者们已经了解到了,pthread_create()接口负责创建了一个线程。
那么线程也属于系统的资源,这跟内存没什么两样,而且线程本身也要占据一定的内存空间。
众所周知的一个问题就是C或C++编程中如果要通过malloc()或new分配了一块内存,就必须使用free()或delete来回收这块内存,否则就会产生著名的内存泄漏问题。
既然线程和内存没什么两样,那么有创建就必须得有回收,否则就会产生另外一个著名的资源泄漏问题,这同样也是一个严重的问题。那么线程的合并就是回收线程资源了。 线程的合并是一种主动回收线程资源的方案。当一个进程或线程调用了针对其它线程的pthread_join()接口,就是线程合并了。
这个接口会阻塞调用进程或线程,直到被合并的线程结束为止。当被合并线程结束,pthread_join()接口就会回收这个线程的资源,并将这个线程的返回值返回给合并者。 与线程合并相对应的另外一种线程资源回收机制是线程分离,调用接口是pthread_detach()。
线程分离是将线程资源的回收工作交由系统自动来完成,也就是说当被分离的线程结束之后,系统会自动回收它的资源。
因为线程分离是启动系统的自动回收机制,那么程序也就无法获得被分离线程的返回值,这就使得pthread_detach()接口只要拥有一个参数就行了,那就是被分离线程句柄。 线程合并和线程分离都是用于回收线程资源的,可以根据不同的业务场景酌情使用。不管有什么理由,你都必须选择其中一种,否则就会引发资源泄漏的问题,这个问题与内存泄漏同样可怕。
线程取消(pthread_cancel)
功能:调用线程终止同进程中,其他的线程,调用该方法后,被终止的线程并不一定立马被终止,只有在下次系统调用或调用了pthread_testcancel()方法后,才真正终止线程。
创建线程
#include<stdio.h> #include<stdlib.h> #include<string.h> #include<pthread.h> #include<unistd.h> #include<sys/types.h> char message[50] = "THREAD_TEST"; void* thread_func(void *arg); int main(){ pthread_t t_thread; void *thread_result; int res; res = pthread_create(&t_thread, NULL, thread_func, (void*)message); if(res != 0){ perror("线程创建失败!"); exit(EXIT_FAILURE); } printf("wait for the thread! "); pthread_join(t_thread, &thread_result); printf("线程已结束,返回值为%s ", (char*)thread_result); printf("message的值为%s ", message); free(thread_result); exit(EXIT_SUCCESS); } void* thread_func(void *arg){ printf("线程正在运行,参数为%s ", (char*)arg); sleep(3); strcpy(message, "线程修改"); char* buf = (char*)malloc(strlen("线程执行完毕!")); strcpy(buf, "线程执行完毕!"); pthread_exit(buf); }
取消线程
#include<stdio.h> #include<string.h> #include<pthread.h> #include<stdlib.h> #include<unistd.h> void *thread_func(void *arg){ int res; res = pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL); if(res != 0){ perror("设置线程取消失败"); exit(EXIT_FAILURE); } if((res = pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, NULL)) != 0){ perror("设置线程取消类型失败!"); exit(EXIT_FAILURE); } printf("子线程正在运行! "); for(int i = 0; i < 10; i++){ sleep(1); printf("子线程正在运行! "); } pthread_exit(EXIT_SUCCESS); } int main(){ int res; pthread_t thread; if((res = pthread_create(&thread, NULL, thread_func, NULL)) != 0){ perror("线程创建失败!"); exit(EXIT_FAILURE); } sleep(3); printf("取消线程! "); if((res = pthread_cancel(thread)) != 0){ perror("取消线程失败!"); exit(EXIT_FAILURE); } exit(EXIT_SUCCESS); }
引用链接:https://blog.csdn.net/hbk320/article/details/49666757
https://www.cnblogs.com/jiu0821/p/6707912.html
https://www.cnblogs.com/fnlingnzb-learner/p/6962868.html
https://www.jianshu.com/p/212dd2a052f3
https://www.cnblogs.com/lijunamneg/archive/2013/01/25/2877211.html