目录

站在内核的角度,OS只有轻量级进程,没有线程的概念,但是站在用户的角度我们只有线程没有轻量级进程的概念。因为Linux下没有真正意义上的线程,而是用进程模拟的线程,所以Linux不会提供直接创建线程的系统调用,最多给我们提供创建轻量级进程的接口。
所以linux对下对LWP的接口进行封装,对上给用户提供线程控制的接口——POSIX线程库,pthread库,这是任何一个linux系统都会带的库,又叫原生线程库。
POSIX线程:
功能:创建一个新的线程。
原型:
int pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine)(void*), void *arg);参数:
- thread:返回线程ID。
- attr:设置线程的属性,attr为NULL表示使用默认属性。
- start_routine:是个函数地址,线程启动后要执行的函数,该函数返回值是void*,参数是void*。
- arg:传给线程启动函数的参数。
返回值:
- 成功返回0;失败返回错误码。
测试代码:
- #include
- #include
- #include
- #include
- using namespace std;
-
- void *FuncRun(void *argc)
- {
- while (1)
- {
- cout << "I am thread,my pid:" << getpid() << endl;
- sleep(1);
- }
- }
-
- int main()
- {
- //线程id
- pthread_t id;
- //创建线程
- pthread_create(&id, NULL, FuncRun, NULL);
- while (1)
- {
- cout << "I am main,my pid:" << getpid() << endl;
- sleep(1);
- }
- return 0;
- }
测试结果:

说明:
查看线程使用命令:
ps -aL

测试代码:
- #include
- #include
- #include
- #include
-
- using namespace std;
-
- void *FuncRun1(void *argc)
- {
- int count = 0;
- while (1)
- {
- count++;
- cout << "I am thread1,my pid:" << getpid() << endl;
- if (count == 5)
- {
- int tmp = count / 0;
- }
- sleep(1);
- }
- }
- void *FuncRun2(void *argc)
- {
- while (1)
- {
- cout << "I am thread2,my pid:" << getpid() << endl;
- sleep(1);
- }
- }
-
- int main()
- {
- // 线程id
- pthread_t id1, id2;
- // 创建线程
- pthread_create(&id1, NULL, FuncRun1, NULL);
- pthread_create(&id2, NULL, FuncRun2, NULL);
-
- while (1)
- {
- cout << "I am main,my pid:" << getpid() << endl;
- sleep(1);
- }
-
- return 0;
- }
测试结果:

说明:
我们想通过给线程函数传参让线程执行更加复杂的任务。
- #include
- #include
- #include
- #include
-
- using namespace std;
-
- // 任务,计算[1-top]的求和,并将结果存储到sum中。
- struct task
- {
- task(int top, int num)
- : _thread_name("thread" + to_string(num)), _top(top), _sum(0), _num(num)
- {
- }
-
- string _thread_name; // 线程名字
- int _top; // 计算数据范围
- int _sum; // 结果
- int _num; // 线程编号
- };
-
- // 线程函数
- void *FuncRun(void *argc)
- {
- task *t = (task *)argc;
- for (int i = 1; i <= t->_top; i++)
- {
- t->_sum += i;
- }
- }
-
- int main()
- {
- // 线程id
- pthread_t id1, id2;
- // 创建线程
-
- task t1(100, 1);
- task t2(150, 2);
-
- pthread_create(&id1, NULL, FuncRun, &t1);
- pthread_create(&id2, NULL, FuncRun, &t2);
- // 等待线程计算完再输出结果
- sleep(1);
-
- cout << t1._thread_name << ":[1-" << t1._top << "]=" << t1._sum << endl;
- cout << t2._thread_name << ":[1-" << t2._top << "]=" << t2._sum << endl;
-
- return 0;
- }
测试结果:

说明:
pthread_t pthread_self(void);
pthread_t 到底是什么类型呢?取决于实现。对于Linux目前实现的NPTL实现而言,pthread_t类型的线程ID,本质就是一个进程地址空间上的一个地址。
我们在对线程做操作的时候,根本上是使用线程库对线程进行操作,那么线程库本质就是存在于linux上的动态库,在我们使用线程库的时候,线程库也会向普通的动态库一样加载到共享区中,我们使用线程库方法就是访问自己的地址空间。
线程库中需要被管理的线程会有很多,线程库也必然实现了线程的数据结构——TCB(线程控制块)。
每个线程都有自己的TCB,和独立的上下文数据,以及线程栈空间。pthread_t 就是指向他们的首地址的一个地址。

如果需要只终止某个线程而不终止整个进程,可以有三种方法:
功能:线程终止.
原型:void pthread_exit(void *value_ptr);
参数:value_ptr:value_ptr不要指向一个局部变量,返回线程结果。
返回值:无返回值,跟进程一样,线程结束的时候无法返回到它的调用者(自身)。
测试代码:
- #include
- #include
- #include
- #include
-
- using namespace std;
-
- void *FuncRun1(void *argc)
- {
- int count = 0;
- while (1)
- {
- count++;
- cout << "I am thread-1-count:" << count << endl;
- sleep(1);
- // 三秒后线程1退出
- if (count == 3)
- {
- pthread_exit(NULL);
- }
- }
- }
-
- void *FuncRun2(void *argc)
- {
- int count = 0;
- while (1)
- {
- count++;
- cout << "I am thread-2-count:" << count << endl;
- sleep(1);
- // 三秒后线程2退出
- if (count == 3)
- {
- pthread_exit(NULL);
- }
- }
- }
-
- int main()
- {
- // 线程id
- pthread_t id1, id2;
- // 创建线程
- pthread_create(&id1, NULL, FuncRun1, NULL);
- pthread_create(&id2, NULL, FuncRun2, NULL);
-
- while (1)
- {
- cout << "I am main,my pid:" << getpid() << endl;
- sleep(1);
- }
-
- return 0;
- }
测试结果:

说明:
功能:取消一个执行中的线程
原型:int pthread_cancel(pthread_t thread);
参数:thread:线程ID
返回值:成功返回0;失败返回错误码
测试代码:
-
- #include
- #include
- #include
- #include
-
- using namespace std;
-
- void *FuncRun1(void *argc)
- {
- int count = 0;
- while (1)
- {
- count++;
- cout << "I am thread-1-count:" << count << endl;
- sleep(1);
- }
- }
- void *FuncRun2(void *argc)
- {
- int count = 0;
- while (1)
- {
- count++;
- cout << "I am thread-2-count:" << count << endl;
- sleep(1);
- }
- }
- int main()
- {
- // 线程id
- pthread_t id1, id2;
- // 创建线程
- pthread_create(&id1, NULL, FuncRun1, NULL);
- pthread_create(&id2, NULL, FuncRun2, NULL);
- int count = 0;
- while (1)
- {
- count++;
- sleep(1);
-
- if (count == 3)
- {
- // 三秒后终止线程
- pthread_cancel(id1);
- pthread_cancel(id2);
- }
- cout << "I am main" << endl;
- }
-
- return 0;
- }
测试结果:

为什么需要线程等待?
功能:等待线程结束。
原型:int pthread_join(pthread_t thread, void **value_ptr);
参数:thread:线程ID。
value_ptr:它指向一个指针,后者指向线程的返回值。
返回值:成功返回0;失败返回错误码。
调用该函数的线程将挂起等待,直到id为thread的线程终止。thread线程以不同的方法终止,通过pthread_join得到的终止状态是不同的,总结如下:
测试代码:
- void *FuncRun1(void *argc)
- {
- int *top = (int *)argc;
- int *sum = new int;
- for (int i = 1; i <= *top; i++)
- {
- *sum += i;
- }
- // 线程退出
- pthread_exit(sum);
- }
-
- void *FuncRun2(void *argc)
- {
- int *top = (int *)argc;
- int *sum = new int;
- for (int i = 1; i <= *top; i++)
- {
- *sum += i;
- }
- // 线程退出
- return sum;
- }
-
- void *FuncRun3(void *argc)
- {
- int *top = (int *)argc;
- int *sum = new int;
- for (int i = 1; i <= *top; i++)
- {
- *sum += i;
- sleep(1);
- }
- free(sum);
- // 线程退出
- }
-
- int main()
- {
-
- int top1 = 100;
- int top2 = 150;
- int top3 = 200;
-
- pthread_t id1;
- pthread_t id2;
- pthread_t id3;
-
- pthread_create(&id1, NULL, FuncRun1, &top1);
- pthread_create(&id2, NULL, FuncRun2, &top2);
- pthread_create(&id3, NULL, FuncRun3, &top3);
- pthread_cancel(id3);
-
- // 接受线程返回数据
- void *ret_ptr1;
- void *ret_ptr2;
- void *ret_ptr3;
- // 等待线程
- pthread_join(id1, &ret_ptr1);
- pthread_join(id2, &ret_ptr2);
- pthread_join(id3, &ret_ptr3);
-
-
- cout << "ret1:" << *((int *)ret_ptr1) << endl;
- free(ret_ptr1);
- cout << "ret2:" << *((int *)ret_ptr2) << endl;
- free(ret_ptr2);
- if (ret_ptr3 == PTHREAD_CANCELED)
- cout << "ret3:PTHREAD_CANCELED" << endl;
-
- return 0;
- }
测试结果:

int pthread_detach(pthread_t thread);
可以是线程组内其他线程对目标线程进行分离,也可以是线程自己分离:
pthread_detach(pthread_self());
joinable和分离是冲突的,一个线程不能既是joinable又是分离的。
测试代码:
-
- #include
- #include
- #include
- #include
- #include
- #include
-
- using namespace std;
- void *FuncRun(void *argc)
- {
- // 线程分离
- pthread_detach(pthread_self());
- int count = 0;
- while (1)
- {
- count++;
- cout << "I am thread-count:" << count << endl;
- sleep(1);
- }
- }
-
- int main()
- {
- pthread_t tid;
- int n = pthread_create(&tid, NULL, FuncRun, NULL);
- if (n != 0)
- {
- cerr << "pthread_create:" << strerror(errno) << endl;
- }
-
- sleep(2);
-
- // 线程已经分离,再去线程等待,pthread_join会立即报错。
- if (pthread_join(tid, NULL) == 0)
- {
- printf("pthread wait success\n");
- }
- else
- {
- printf("pthread wait failed\n");
- }
-
- return 0;
- }
测试结果:

我们对线程操作有了一定的理解,但是线程各种操作还是有些繁琐,我们可以用类将线程封装,仅仅通过成员函数就可以完成对线程的控制。
- #pragma once
- #include
- #include
- #include
- #include
- #include
- #include
-
- using namespace std;
-
- typedef enum Status
- {
- NEW = 0,
- EXIT,
- RUNNING
- } Status;
-
- class Thread
- {
- private:
- typedef void *(*Func)(void *);
-
- public:
- // 构造函数
- Thread(int num, Func func, void *args)
- : _func(func), _args(args)
- {
- char __name[50] = {0};
- sprintf(__name, "thread-%d", num);
- _name = __name;
- _status = NEW;
- }
-
- // 如果类的回调函数是一个类的成员函数,那么这个成员函数需要是一个
- // 静态成员函数,因为普通成员函数有this指针的干扰
- static void *RunFunc(void *args)
- {
- Thread *ts = static_cast
(args); - return (*ts)();
- }
-
- void *operator()()
- {
- return _func(_args);
- }
-
- // 线程开始执行
- void run()
- {
- pthread_create(&_tid, NULL, RunFunc, this);
- _status = RUNNING;
- }
-
- // 线程等待
- void *join()
- {
- void **ret = (void **)new void *;
- pthread_join(_tid, ret);
- _status = EXIT;
- return *ret;
- }
-
- // 返回线程的名字
- string name()
- {
- return _name;
- }
-
- ~Thread()
- {
- }
-
- private:
- Func _func; // 回调的函数
- string _name; // 线程名称
- pthread_t _tid; // 线程id
- Status _status; // 线程状态
- void *_args; // 线程回调函数的参数
- };