01 内核不是进程,而是系统

说白了,Linux内核其实很简单,它不是进程,而是操作系统的特权执行环境。
先说最重要的,内核是驻留内存的特权环境,从系统引导时加载,负责管理硬件与软件的交互。
比如,去年我们跑的那个项目,内核空间与用户空间的分离,这是图1 -1 中展示的。
另外一点,内核代码在三种场景下运行:系统调用、中断处理和内核线程。
举个例子,大概3 000量级的中断处理,内核立即响应并处理硬件事件。
我一开始也以为内核就像进程一样可以启动或停止,后来发现不对,内核始终存在于内存中,不参与进程调度。
还有个细节挺关键的,内核通过start_kernel()完成初始化,之后成为响应式执行层,仅在特定情况下被调用。
比如,用户进程发起系统调用时,内核切换至特权模式执行请求,完成后返回用户态。
内核线程的动态管理也是一大特色,基础线程在系统启动时创建,根据系统负载动态扩展。
这个点很多人没注意,其实现代Linux系统可能同时运行1 00-1 5 0个内核线程。
与进程的根本区别在于,内核不可调度,拥有最高权限,而进程运行在用户态,权限受限。
存在形式上,内核是“被进入”的执行环境,而非独立运行的任务。
所以,Linux内核是系统的核心执行环境,通过系统调用、中断处理和内核线程与硬件和用户进程交互,始终驻留内存并保持特权控制。
我觉得值得试试,理解内核的工作机制对深入掌握Linux系统至关重要。

Linux线程及同步

哎哟,这玩意儿我当年刚接手那个项目时也头疼过。
Linux多线程这东西,说简单也简单,说复杂吧,里面坑确实多。

我跟你讲,那会儿我在北京,有个系统,做数据处理的。
一上来就给分配了几个任务,其中一个就是用多线程提高效率。
想着多开几个线程,数据跑得快一点,结果跑着跑着,系统就卡了,CPU跑满,内存也爆了。

一开始我以为是算法问题,后来一查,哦,是多线程出问题了。
你想想,那几个线程都在跑,都在改那个共享的计数器 i,没个啥规矩,肯定乱套了。
你这边刚改完,他那边又改了,最后数据对不上号,整个系统就卡在那儿了。

这时候才明白,光有多个线程跑是不够的,还得有“规矩”,得有个东西管着,谁在用这个共享资源的时候,其他人得等一等,或者看看这个资源是不是已经被占了。
这就像咱们楼下那个公共厨房,做饭的人多,你得有个家伙什儿(比如那个大勺子)来管着,不能一个人抢着用,不然就乱了套。

所以啊,你说的这互斥锁 pthread_mutex_t 就派上用场了。
初始化一个锁,谁要用共享资源了,就得先 pthread_mutex_lock 上锁,用完了再 pthread_mutex_unlock 解锁。
这玩意儿用得不好,后果很严重。
我见过最惨的一次,一个线程没来得及解锁,另一个线程就冲进去了,数据错乱,最后还得重启系统。
那叫一个折腾。

还有那个 pthread_join,也是挺重要的。
你得知道哪个线程什么时候该退,不然有些线程跑着跑着就没影了,资源也释放不了,系统也清理不干净。
记得有一次,我忘了 join 一个线程,结果那个线程占用的内存,好几个月都清理不掉,最后系统监控一看,嚯,一堆僵尸进程,把运维小哥都快急疯了。

说真的,多线程这东西,用好了能提效,用不好,那真是坑爹。
你得多跑跑实验,多看看错误日志,慢慢就摸出门道了。
别像我当年那样,一头扎进去,问题一堆堆的。

Linux系统编程-(pthread)线程创建与使用

2 02 2 年,我接了一个项目,要在某个城市用Linux系统编程实现一个多线程的应用。
一开始,我得搞明白线程和进程的区别,调度单位不同,进程是调度最小单位,而线程是进程内的最小单位。
资源管理上,进程要独立分配资源,而线程共享这些资源,所以线程创建开销小。

然后,我看了通信机制,进程间通信得通过内核,而线程间可以直接通信,效率更高。
终止处理也不同,进程终止要用wait(),而线程终止用pthread_join()。
我当时也懵,不过后来就明白了。

接着,我学习线程创建和基本操作。
用pthread_create函数创建线程,参数有线程标识符指针、线程属性、线程入口函数和参数。
编译的时候得链接-lpthread库,否则程序跑不起来。

创建线程的例子是这样的: c include include include
void thread_func(void arg) { while(1 ) { printf("线程运行中...\n"); sleep(2 ); } return NULL; }
int main() { pthread_t tid; if (pthread_create(&tid, NULL, thread_func, NULL)) { perror("线程创建失败"); return -1 ; } pthread_join(tid, NULL); // 等待线程结束 return 0; }
这代码里,我创建了一个线程,它无限循环地打印信息。

然后,我研究了线程终止方式,显式终止用pthread_exit,隐式终止是线程函数执行完毕自动终止。
主线程退出也会导致所有线程终止,但这不推荐。

线程回收用pthread_join,它阻塞调用直到目标线程终止,回收线程资源。
回收线程的例子是这样的: c void thread_ret(void arg) { pthread_exit("线程正常退出"); }
int main() { pthread_t tid; void ret_val; pthread_create(&tid, NULL, thread_ret, NULL); pthread_join(tid, &ret_val); printf("线程返回值:%s\n", (char)ret_val); return 0; }
这代码里,我创建了一个线程,它退出时返回了一个字符串。

高级管理里,线程分离状态用pthread_detach设置,线程终止后自动释放资源,避免僵尸线程。
获取当前线程ID用pthread_self。

线程取消机制用pthread_cancel请求取消指定线程,目标线程需在取消点响应。

资源清理,我用了pthread_cleanup_push和pthread_cleanup_pop。
线程退出或被取消时,会执行清理函数。

最后,我总结了线程编程的最佳实践,比如资源管理要避免线程泄漏,错误处理要检查函数返回值,参数传递要用结构体封装,同步机制要用互斥锁和条件变量,编译选项要链接-lpthread库,并启用警告。

这整个过程,我学到了很多,也发现了很多潜在的问题,比如线程安全问题和资源竞争条件。
这让我对Linux系统编程有了更深的理解。