Linux之线程控制

打印 上一主题 下一主题

主题 1520|帖子 1520|积分 4560

目录

一、POSIX线程库
二、线程的创建
三、线程等待
四、线程终止
五、分离线程
六、线程ID:pthread_t
1、获取线程ID
2、pthread_t
七、线程局部存储:__thread


一、POSIX线程库

由于Linux下的线程并没有独立特有的布局,所以Linux并没有提供线程相关的接口。
而我们所说的,pthread线程库是应用层的原生线程库。这个线程库并不是体系接口直接提供的,而是由第三方帮我们提供的。
1、与线程有关的函数构成了一个完整的系列,绝大多数函数的名字都是以“pthread_”打头的
2、要使用这些函数库,要通过引入头文<pthread.h>
3、链接这些线程函数库时要使用编译器下令的“-lpthread”选项
二、线程的创建

pthread_create:其功能就是创建线程。
  1. NAME
  2.        pthread_create - create a new thread
  3. SYNOPSIS
  4.        #include <pthread.h>
  5.        int pthread_create(pthread_t *thread, const pthread_attr_t *attr,
  6.                           void *(*start_routine) (void *), void *arg);
  7.        Compile and link with -pthread.
复制代码
参数分析:
thread:获取创建成功的线程ID,该参数是一个输出型参数。
attr:用于设置创建线程的属性,传入nullptr表现使用默认属性。(我们一样平常不关心,直接设为nullptr)
start_routine:该参数是一个函数指针,表现线程启动后要执行的函数。
arg:传给线程执行函数的参数。
返回值:线程创建成功返回0,失败返回错误码。返回值也可以自己设置,返回给主线程。主线程通过pthread_join获取。
   主线程:当一个程序启动时,就有一个进程被操作体系创建,与此同时一个线程也立刻运行,这个线程就叫做主线程。
  下面我们让主线程调用pthread_create函数创建一个新线程:
  1. #include <iostream>
  2. #include <unistd.h>
  3. #include <pthread.h>
  4. using namespace std;
  5. void *thread_run(void *argc)
  6. {
  7.     cout << "new thread pid: " << getpid() << "\n"
  8.          << endl;
  9.     sleep(20);
  10.     return nullptr;
  11. }
  12. int main()
  13. {
  14.     pthread_t tid;
  15.     pthread_create(&tid, nullptr, thread_run, (void *)"thread 1");
  16.     while (true)
  17.     {
  18.         cout << "main thread pid: " << getpid() << endl;
  19.         sleep(1);
  20.     }
  21.     return 0;
  22. }
复制代码
 

使用ps -aL下令,可以表现当前的轻量级进程。

从上图,我们看到两个线程的PID相同,分析他们属于同一个进程。但是他们的LWP值不同,分析他们是两个不同的线程。LWP就是轻量级进程的ID。
注:在Linux中,线程与内核的LWP是一一对应的,实际上操作体系调度的时间是根据LWP调度的,而不是PID,只不外我们之前接触到的都是单线程进程,其PID和LWP是相等的,所以对于单线程进程来说,调度时采用PID和LWP是一样的。
我们也可以让一个主线程创建多个新线程
  1. #include <iostream>
  2. #include <unistd.h>
  3. #include <string>
  4. #include <pthread.h>
  5. using namespace std;
  6. void *thread_run(void *argc)
  7. {
  8.     string name = (char *)argc;
  9.     while (true)
  10.     {
  11.         cout << name << "---"
  12.              << "pid: " << getpid() << "\n"
  13.              << endl;
  14.         sleep(1);
  15.     }
  16. }
  17. int main()
  18. {
  19.     pthread_t tid[5];
  20.     char name[64];
  21.     for (int i = 0; i < 5; i++)
  22.     {
  23.         snprintf(name, sizeof(name), "%s-%d", "thread", i);
  24.         pthread_create(tid + i, nullptr, thread_run, (void *)name);
  25.         sleep(1);
  26.     }
  27.     while (true)
  28.     {
  29.         cout << "main thread pid: " << getpid() << endl;
  30.         sleep(3);
  31.     }
  32.     return 0;
  33. }
复制代码

由于主线程和五个新线程都属于同一个进程,所以它们的PID都是一样的。 
三、线程等待

一个线程被创建出来,那么这个线程就如同进程一样平常,也是必要被等待的。如果主线程不对新线程举行等待,那么这个新线程的资源也是不会被回收的。如果不等待会产生类似于“僵尸进程”的标题,也就会造成内存走漏。所以线程必要被等待。
pthread_join:其功能就是举行线程等待
  1. NAME
  2.        pthread_join - join with a terminated thread
  3. SYNOPSIS
  4.        #include <pthread.h>
  5.        int pthread_join(pthread_t thread, void **retval);
  6.        Compile and link with -pthread.
复制代码
参数分析:
thread:被等待线程的ID。
retval:线程退出时的退出码信息。
返回值:线程等待成功返回0,失败返回错误码。
  1. #include <iostream>
  2. #include <unistd.h>
  3. #include <string>
  4. #include <pthread.h>
  5. using namespace std;
  6. void *thread_run(void *argc)
  7. {
  8.     int count = 10;
  9.     while (true)
  10.     {
  11.         sleep(1);
  12.         if (count++ == 10)
  13.             break;
  14.     }
  15.     cout << "new thread  done ... quit" << endl;
  16.     return nullptr;
  17. }
  18. int main()
  19. {
  20.     pthread_t tid;
  21.     pthread_create(&tid, nullptr, thread_run, (void *)"thread1");
  22.     pthread_join(tid, nullptr);
  23.     cout << "main thread wait done ... quit" << endl;
  24.     return 0;
  25. }
复制代码

第二个参数是用来获取新线程返回值的。主线程可以通过新线程的返回值拿到新线程的计算结果(该结果也可以保存在堆空间上)
  1. include <iostream>
  2. #include <unistd.h>
  3. #include <string>
  4. #include <pthread.h>
  5. using namespace std;
  6. void *thread_run(void *argc)
  7. {
  8.     int count = 10;
  9.     while (true)
  10.     {
  11.         sleep(1);
  12.         if (count++ == 10)
  13.             break;
  14.     }
  15.     cout << "new thread  done ... quit" << endl;
  16.     return (void *)10;
  17. }
  18. int main()
  19. {
  20.     pthread_t tid;
  21.     pthread_create(&tid, nullptr, thread_run, (void *)"thread1");
  22.     void *ret = nullptr;
  23.     pthread_join(tid, &ret);
  24.     cout << "main thread wait done ... quit"
  25.          << " " << (long long)ret << endl;
  26.     return 0;
  27. }
复制代码

四、线程终止

return:最简朴的终止线程的方式,就是使用return返回一个返回值来终止线程。
pthread_exit:其功能就是终止一个线程。(终止线程不能使用exit,由于它是用来终止进程的)
参数,retval:设置退出结果。
  1. NAME
  2.        pthread_exit - terminate calling thread
  3. SYNOPSIS
  4.        #include <pthread.h>
  5.        void pthread_exit(void *retval);
  6.        Compile and link with -pthread.
复制代码
  1. #include <iostream>
  2. #include <unistd.h>
  3. #include <string>
  4. #include <pthread.h>
  5. using namespace std;
  6. void *thread_run(void *argc)
  7. {
  8.     int count = 10;
  9.     while (true)
  10.     {
  11.         sleep(1);
  12.         if (count++ == 10)
  13.             break;
  14.     }
  15.     cout << "new thread  done ... quit" << endl;
  16.     pthread_exit((void*)17);
  17. }
  18. int main()
  19. {
  20.     pthread_t tid;
  21.     pthread_create(&tid, nullptr, thread_run, (void *)"thread1");
  22.     void *ret = nullptr;
  23.     pthread_join(tid, &ret);
  24.     cout << "main thread wait done ... quit"
  25.          << " " << (long long)ret << endl;
  26.     return 0;
  27. }
复制代码
 

pthread_cancel:其功能是取消一个线程。
参数,thread:线程ID。
  1. NAME
  2.        pthread_cancel - send a cancellation request to a thread
  3. SYNOPSIS
  4.        #include <pthread.h>
  5.        int pthread_cancel(pthread_t thread);
  6.        Compile and link with -pthread.
复制代码
  1. #include <iostream>
  2. #include <unistd.h>
  3. #include <string>
  4. #include <pthread.h>
  5. using namespace std;
  6. void *thread_run(void *argc)
  7. {
  8.     string name = (char *)argc;
  9.     int count = 10;
  10.     while (true)
  11.     {
  12.         sleep(1);
  13.         if (count++ == 10)
  14.             break;
  15.     }
  16.     cout << "new thread  done ... quit" << endl;
  17. }
  18. int main()
  19. {
  20.     pthread_t tid;
  21.     pthread_create(&tid, nullptr, thread_run, (void *)"thread1");
  22.     void *ret = nullptr;
  23.     pthread_cancel(tid);
  24.     pthread_join(tid, &ret);
  25.     cout << "main thread wait done ... quit"
  26.          << " " << (long long)ret << endl;
  27.     return 0;
  28. }
复制代码
 

线程被取消,线程等待时获取的退出码为-1。 
五、分离线程

新线程退出后,主线程必要对其举行pthread_join操作,否则无法释放资源,从而造成内存走漏。
但如果主线程不关心新线程的返回值,此时我们可以将该新线程举行分离,后续当新线程退出时就会自动释放线程资源。
一个线程如果被分离了,这个线程依旧要使用该进程的资源,依旧在该进程内运行,甚至这个线程崩溃了肯定会影响其他线程,只不外这个线程退出时不再必要主线程去join了,当这个线程退出时体系会自动回收该线程所对应的资源。
pthread_detach:其功能就是举行分离线程。一样平常是线程自己分离。
  1. int pthread_detach(pthread_t thread);
复制代码
参数分析:thread:被分离线程的ID。
返回值分析:
线程分离成功返回0,失败返回错误码。
  1. #include <iostream>
  2. #include <unistd.h>
  3. #include <string>
  4. #include <pthread.h>
  5. using namespace std;
  6. void *thread_run(void *argc)
  7. {
  8.     pthread_detach(pthread_self());
  9.     int count = 10;
  10.     while (true)
  11.     {
  12.         sleep(1);
  13.         if (count++ == 10)
  14.             break;
  15.     }
  16.     cout << "new thread  done ... quit" << endl;
  17.     pthread_exit((void*)17);
  18. }
  19. int main()
  20. {
  21.     pthread_t tid;
  22.     pthread_create(&tid, nullptr, thread_run, (void *)"thread1");
  23.     void *ret = nullptr;
  24.     cout << "main thread wait done ... quit"
  25.          << " " << (long long)ret << endl;
  26.     return 0;
  27. }
复制代码

 如果我们在线程分离了之后,任然等待,会怎么样呢?
  1. #include <iostream>
  2. #include <unistd.h>
  3. #include <cerrno>
  4. #include <cstring>
  5. #include <pthread.h>
  6. using namespace std;
  7. void *thread_run(void *argc)
  8. {
  9.     pthread_detach(pthread_self());
  10.     int count = 9;
  11.     while (true)
  12.     {
  13.         sleep(1);
  14.         if (count++ == 10)
  15.             break;
  16.     }
  17.     cout << "new thread  done ... quit" << endl;
  18.     pthread_exit((void *)17);
  19. }
  20. int main()
  21. {
  22.     pthread_t tid;
  23.     pthread_create(&tid, nullptr, thread_run, (void *)"thread1");
  24.     sleep(2);
  25.     int n = pthread_join(tid, nullptr);
  26.     cout << "n: " << n << "errstring: " << strerror(n) << endl;
  27.     return 0;
  28. }
复制代码

六、线程ID:pthread_t

pthread_create函数会产生一个线程ID,存放在第一个参数指向的地址中,该线程ID和内核中的LWP是完全不一样的。内核中的LWP属于进程调度的范畴,必要一个数值来唯一表现该线程。
那么pthread_t到底是什么类型呢?
1、获取线程ID

pthread_self:获取线程的ID。
  1. #include <iostream>
  2. #include <unistd.h>
  3. #include <cerrno>
  4. #include <cstring>
  5. #include <pthread.h>
  6. using namespace std;
  7. void *thread_run(void *argc)
  8. {
  9.     int count = 9;
  10.     while (true)
  11.     {
  12.         sleep(1);
  13.         if (count++ == 10)
  14.             break;
  15.     }
  16.     cout << "new thread  done ... quit"
  17.          << "new thread ID: " << pthread_self() << endl;
  18.     pthread_exit((void *)17);
  19. }
  20. int main()
  21. {
  22.     pthread_t tid;
  23.     pthread_create(&tid, nullptr, thread_run, (void *)"thread1");
  24.     void *ret = nullptr;
  25.     sleep(2);
  26.     cout << "main thread ID: " << pthread_self() << endl;
  27.     pthread_join(tid, &ret);
  28.     return 0;
  29. }
复制代码

为什么线程的ID数值这么大呢?下面我们就来讲一讲。 
2、pthread_t

进程运行时线程动态库被加载到内存,然后通过页表映射到进程地址空间中的共享区,此时该进程内的全部线程都是能看到这个动态库的。

其中主线程采用的栈是进程地址空间中原生的栈,而其余线程采用的栈就是由线程库帮我们在共享区中开辟的。
线程库给每个新线程提供属于自己的struct pthread,当中包含了对应线程的各种属性;每个线程还有自己的线程局部存储,当中包含了对应线程被切换时的上下文数据。其中,还有线程栈。如下图:

所以,线程ID本质就是进程地址空间共享区上对应的struct pthread的虚拟地址。 
七、线程局部存储:__thread

假设有一个全局变量:g_val。我们知道,各个线程是共享全局变量的。不同的线程可以对同一个全局变量举行操作。那么如果我们想让每个线程都拥有属于自己的g_val,那么我们可以加上关键字:__thread。这种现象就叫做线程局部存储。

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

慢吞云雾缓吐愁

论坛元老
这个人很懒什么都没写!
快速回复 返回顶部 返回列表