创建线程:成功返回零,否则返回非零值
#include <pthread.h>
int pthread_create( pthread_t * thread,
const pthread_attr_t * attr,
void * (*start_routine)(void*),
void * arg);
等待线程:一直阻塞调用它的线程,直至目标线程执行结束
#include <pthread.h>
int pthread_join(pthread_t thread, void **retval);
调用 pthread_join 的线程会阻塞,直到目标线程终止。
提纲
1 void *mythread(void *arg) {
2 printf("%s\n", (char *) arg);
3 return NULL;
4 }
5 int main(int argc, char *argv[]) {
6 pthread_t p1, p2;
7 int rc;
8 printf("main: begin\n");
9 rc = pthread_create(&p1, NULL, mythread, "A"); assert(rc == 0);
10 rc = pthread_create(&p2, NULL, mythread, "B"); assert(rc == 0);
11 // join waits for the threads to finish
12 rc = pthread_join(p1, NULL); assert(rc == 0);
13 rc = pthread_join(p2, NULL); assert(rc == 0);
14 printf("main: end\n");
15 return 0;
16 }
一个程序,它创建两个线程,每个线程都做了一些独立的工作,在这例子中,打印“A”或“B”。
❯ ./t0
main: begin
A
B
main: end
提纲
4.2 内核态管理且用户态运行的线程
4.3 内核态管理且内核态运行的线程
4.4 混合管理且运行的线程
由一组用户级的线程库函数来完成线程的管理,包括线程的创建、终止、同步和调度等
提纲
4.1 用户态管理且用户态运行的线程
4.3 内核态管理且内核态运行的线程
4.4 混合管理且运行的线程
Windows NT 内核支持线程,每个线程都是内核对象
Linux-2.6 + glibc-2.3开始支持POSIX thread标准
rCore/uCore内核的设计
主流:一个用户线程对应一个内核的线程控制块,由内核管理和调度
线程是调度的基本单位,而进程则是资源拥有的基本单位。
fork()
引起的问题多线程应用程序中,建议谨慎使用 fork()
fork()
,会导致子进程继承这个状态和资源的不一致性。例如全局变量被多个线程修改fork()
,可能导致子进程无法获得该锁而导致死锁。例如子进程中没有持有锁的线程会死锁。fork()
会复制整个进程的地址空间,包括所有线程所拥有的栈、寄存器和锁等资源fork()
的开销较大,可能会影响应用程序的性能可采用:限制线程中调用 fork()、使用 pthread_atfork() 在 fork() 前后统一加/解锁来防止子进程死锁等方法,来避免这些问题。
提纲
4.1 用户态管理且用户态运行的线程
4.2 内核态管理且用户态运行的线程
4.4 混合管理且运行的线程
提纲
4.1 用户态管理且用户态运行的线程
4.2 内核态管理且用户态运行的线程
4.3 内核态管理且内核态运行的线程
轻量级进程(Light-Weight Process,LWP)

线程能够利用的表空间和堆栈空间比内核级线程多。
因此,在多线程应用程序中,建议谨慎使用 fork(),尤其是当涉及到共享资源和锁时。可以采用其他技术来实现进程间通信和同步,例如共享内存、消息队列和信号量等。