共计 4044 个字符,预计需要花费 11 分钟才能阅读完成。
Linux 多线程编程
线程概念
线程是指运行中的程序的调度单位。一个线程指的是过程中一个繁多程序的控制流,也被称为轻量级线程。它是零碎独立调度和调配的根本单位。同一过程中的多个线程将共享该零碎中的全副系统资源,比方文件描述符和信号处理等。一个过程能够有很多线程,每个线程并行执行不同的工作。
线程与过程比拟
① 和过程相比,它是一种十分“勤俭”的多任务操作形式。在 Linux 零碎中,启动一个新的过程必须调配给它独立的地址空间,建设泛滥的数据表来保护其代码段、堆栈段和数据段,这种多任务工作形式的代价十分“低廉”。而运行于一个过程中的多个线程,它们彼此之间应用雷同的地址空间,共享大部分数据,启动一个线程所破费的空间远远小于启动一个过程所破费的空间,而且线程间彼此切换所须要工夫也远远小于过程间切换所须要的工夫。
② 线程间不便的通信机制。对不同过程来说它们具备独立的数据空间,要进行数据的传递只能通过通信的形式进行。这种形式不仅费时,而且很不不便。线程则不然,因为同一过程下的线程之间共享数据空间,所以一个线程的数据能够间接为其余线程所用,不仅不便,而且快捷。
线程根本编程
Linux 零碎下的多线程遵循 POSIX 线程接口,称为 pthread。编写 Linux 下的多线程程序,须要应用头文件 pthread.h,连贯时须要应用库 libpthread.a。因为 pthread 的库不是 Linux 零碎的库,所以在编译时要加上 -lpthread。例如:gcc filename -lpthread。留神,这里要讲的线程相干操作都是用户空间中的线程的操作。
线程创立:创立线程实际上就是确定调用该线程函数的入口点,这里通常应用的函数是 pthread_create()。在线程创立后,就开始运行相干的线程函数。
线程退出:在线程创立后,就开始运行相干的线程函数,在该函数运行完之后,该线程也就退出了,这也是线程退出的一种办法。另一种退出线程的办法是应用函数 pthread_exit(),这是线程的被动行为。这里要留神的是,在应用线程函数时,不能随便应用 exit()退出函数来进行出错解决。因为 exit()的作用是使调用过程终止,而一个过程往往蕴含多个线程,因而,在应用 exit()之后,该过程中的所有线程都终止了。在线程中就能够应用 pthread_exit()来代替过程中的 exit()。
线程期待:因为一个过程中的多个线程是共享数据段的,因而,通常在线程退出后,退出线程所占用的资源并不会随着线程的终止而失去开释。正如过程之间能够用 wait()零碎调用来同步终止并开释资源一样,线程之间也有相似机制,那就是 pthread_join()函数。pthread_join()用于将以后过程挂起来期待线程的完结。这个函数是一个线程阻塞的函数,调用它的函数将始终期待到被期待的线程完结为止,当函数返回时,被期待线程的资源就被发出。
线程勾销:后面曾经提到线程调用 pthread_exit()函数被动终止本身线程,然而在很多线程利用中,常常会遇到在别的线程中要终止另一个线程的问题,此时调用 pthread_cancel()函数来实现这种性能,但在被勾销的线程的外部须要调用 pthread_setcancel()函数和 pthread_setcanceltype()函数设置本人的勾销状态。例如,被勾销的线程接管到另一个线程的勾销申请之后,是承受函数疏忽这个申请;如果是承受,则再判断立即采取终止操作还是期待某个函数的调用等。
线程标识符获取:获取调用线程的标识 ID。
线程革除:线程终止有两种状况:失常终止和非正常终止。线程被动调用 pthread_exit()或者从线程函数中 return 都将使线程失常退出,这是可预感的退出形式;非正常终止是线程在其它线程的干涉下,或者因为本身运行出错 (比方拜访非法地址) 而退出,这种退出形式是不可预感的。不论是可预感的线程终止还是异样终止,都回存在资源开释的问题,如何保障线程终止时能顺利地开释掉本人所占用的资源,是一个必须思考的问题。
从 pthread_cleanup_push()的调用点到 pthread_cleanup_pop()之间的程序段中的终止动作 (包含调用 pthread_exit() 和异样终止,不包含 return)都将执行 pthread_cleanup_push()所指定的清理函数。
Linuxc/c++ 服务器开发高阶视频学习材料 +qun720209036 获取
更多视频内容包含 C /C++,Linux,Nginx,ZeroMQ,MySQL,Redis,MongoDB,ZK,流媒体,P2P,K8S,Docker,TCP/IP,协程,DPDK 多个高级知识点分享。
视频链接:C/C++Linux 服务器开发 / 后盾架构师 - 学习视频
1、如何利用 2 个条件变量实现线程同步?
思路:就是来回的利用 pthread_cond_signal()函数,当一方被阻塞时,唤醒函数能够唤醒 pthread_cond_wait()函数,只不过 pthread_cond_wait()这个办法要执行其后的语句,必须遇到下一个阻塞 (也就是 pthread_cond_wait() 办法时),才执行唤醒后的其后语句。
代码如下:
include<stdio.h>
include<unistd.h>
include<stdlib.h>
include<string.h>
include<pthread.h>
define MAX_NUM 2static int count = 1;pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;pthread_cond_t js = PTHREAD_COND_INITIALIZER;pthread_cond_t os = PTHREAD_COND_INITIALIZER;void A(void arg){
pthread_mutex_lock(&mutex);
while(count <= MAX_NUM)
{
if(count%2 == 1){
printf(“A = %dn”, count);
count++;
pthread_cond_signal(&os);
sleep(5);
printf(“bbbbbbbbbbbbbbbbbbbbbbbbbbbn”);
}else{
printf(“cccccccccccccccccccccccccccn”);
pthread_cond_wait(&js, &mutex);
printf(“dddddddddddddddddddddddddddn”);
}
pthread_mutex_unlock(&mutex);
}}
void B(void arg)
{
pthread_mutex_lock(&mutex);
while(count <= MAX_NUM){
if(count%2 == 0){
printf(“B = %dn”, count);
count++;
pthread_cond_signal(&js);
}
else
{
pthread_cond_wait(&os, &mutex);
printf(“aaaaaaaaaaaaaaaaaaaaaaaaaaaan”);
}
}
pthread_mutex_unlock(&mutex);
}
int main(void)
{
pthread_t tid1, tid2;
pthread_create(&tid2, NULL, B, NULL);
sleep(1);
pthread_create(&tid1, NULL, A, NULL);
pthread_join(tid1, NULL);
pthread_join(tid2, NULL);
return 0;
}
运行后果
下面的这个程序就是:2 个条件变量对一个互斥量的操作。signal()发送唤醒 wait(),wait()之后的语句临时不执行,直到下一次遇到 wait()时,阻塞,返回执行唤醒的 wait()之后的语句。
2、怎么创立 10 个线程的开始运行和完结过程?
利用 2 个条件变量和 1 个互斥量即可实现。
代码如下:
include<stdio.h>
include<unistd.h>
include<stdlib.h>
include<string.h>
include<pthread.h>
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;pthread_cond_t cond1 = PTHREAD_COND_INITIALIZER;void thread_fun1(void arg){
int i = (int )arg;
pthread_mutex_lock(&mutex);
printf(“[%d] thread start upn”, i);
pthread_cond_wait(&cond, &mutex);
printf(“[%d]thread is wake upn”, i);
pthread_mutex_unlock(&mutex);
}
void thread_fun2(void arg)
{
pthread_cond_broadcast(&cond); // 播送,一次唤醒所有的线程}int main(void){
pthread_t tid1[10], tid2;
int i;
for(i = 0; i < 10; i++)
{
pthread_create(&tid1[i], NULL, thread_fun1, &i);// 创立 10 个线程
sleep(1);
}
pthread_create(&tid2, NULL, thread_fun2, NULL);// 创立 1 个线程
for(i = 0; i < 10; i++)
{// 主线程等子线程执行完
pthread_join(tid1[i], NULL);
}
pthread_join(tid2, NULL);
return 0;
}
运行后果
多线程的编程中:互斥量、条件变量是重中之重!!!