系统级程序设计第五课内容——Linux线程管理 2022.5.23

系统级程序设计第五课内容——Linux线程管理


前言

本节课主要学习了在Linux系统下对线程的一系列操作,理解了线程与进程的差别,学习在线程的管理上与进程不同的地方。


一、创建线程

Linux系统中创建线程的系统调用接口为 pthread_create(),该函数存在于函数库pthread.h中,具体形式如下:

int pthread_create(
									pthread_t *thread, 
									const pthread_attr_t *attr, 
									void *(*start_routine)(void *), 
									void *arg  );

参数说明:
thread:一个传入传出参数,待创建线程的id指针;
attr:设置待创建线程的属性,通常传入NULL;
start_routine:一个函数指针,指向一个参数为void *,返回值也为void *的函数,该函数为待创建线程的执行函数;
arg:传给线程执行函数的参数。

线程调用pthread_create函数创建新线程后,当前线程会从pthread_create函数返回并继续向下执行,新线程执行函数指针start_routine所指的函数。
该函数创建成功返回0,创建失败返回errno。与进程不同的地方,接收错误信息时,需要先自定义变量接收errno,再调用strerror()将获取的错误代码转换成错误信息。

注意:线程id的类型pthread_t并非是一个正整数,只在当前进程中保证唯一。

代码举例如下:

#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <unistd.h>
void *tfn(void *arg) {
	printf("tfn--pid=%d,tid=%lu\n", getpid(), pthread_self());
	return (void*)0;
}//of tfn
int main() {
	pthread_t tempTid;
	printf("main--pid=%d, tid=%lu\n", getpid(), pthread_self());
	int tempRet = pthread_create(&tempTid, NULL, tfn, NULL);
	if (tempRet != 0){
		fprintf(stderr, "pthread_create error.");
		exit(1);
	}//of if
	sleep(1);
	return 0;
}//of main

在这里插入图片描述


二、测试进程与线程的区别

1、进程必须独立占用一段地址,而统一进程中的不同线程占用同一段地址。
2、全局变量在进程中不是共享的,但在线程中是共享的。

代码举例如下:

#include <stdio.h>
#include <pthread.h>
#include <stdlib.h>
#include <unistd.h>
int globVar = 100;
void *tfn(void *arg) {
	globVar = 200;
	printf("thread\n");
	return NULL;
}//of tfn
int main(void) {
	printf("At first var = %d\n", globVar);
	pthread_t tempTid;
	pthread_create(&tempTid, NULL, tfn, NULL);
	sleep(1);
	printf("after pthread_create, var = %d\n", globVar);
	printf("------finished-------");
	return 0;
}//of main

在这里插入图片描述


三、线程退出

线程中提供了一个用于单个线程退出的函数——pthread_exit ,位于函数库pthread.h中,具体形式如下:

void pthread_exit(void *retval);//参数retval表示线程的退出状态,通常设置为NULL。

之前学到的两种退出返回函数,return用于退出函数,exit用于退出进程,这两个都不能用来退出线程。

代码举例如下:分别用pthread_exit, return, exit使其中一个线程退出,观察其它线程的执行状况。

#include <pthread.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
void *tfn(void *paraArg) {
	long int i;
	i = (long int)paraArg;
	if (i == 2) {
		pthread_exit(NULL);
	}//of if
	sleep(i);
	printf("I'm %ld th thread, Thread_ID = %lu\n", i + 1, pthread_self());
	return NULL;
}//of tfn
int main(int paraArgc, char *paraArgv[]) {
	long int tempNum = 5, i;
	pthread_t tempTid;
	if (paraArgc == 2) {
		tempNum = atoi(paraArgv[1]);
	}//of if
	for (i = 0; i < tempNum; i++) {
		pthread_create(&tempTid, NULL, tfn, (void *)i);
	}//of for i
	sleep(tempNum);
	printf("I am main, I'm a thread!  main_thread_ID = %lu\n", pthread_self());
	return 0;
}//of main

在这里插入图片描述


四、线程终止

在线程操作中有一个与终止进程的函数kill()对应的系统调用函数pthread_cancel,该函数通过向制定线程发送CANCEL信号,使一个线程强行杀死另外一个线程。该函数位于函数库pthread.h中,具体形式如下:

int pthread_cancel(pthread_t thread);//参数thread为线程id。

与进程不同的是,调用该函数杀死线程时,需要等待线程到达某个取消点,线程才会成功被终止;
取消点通常伴随阻塞出现,用户也可以在程序中通过调用pthread_testcancel函数创造取消点;
pthread_exit使线程主动退出,pthread_cancel通过信号使线程被动退出;

注意:由于线程机制出现之前信号机制已经出现,信号机制在创建时并未考虑线程,线程与信号机制的兼容性略有不足,因此多线程编程时尽量避免使用信号,以免出现难以调试的错误。

代码举例如下:

#include <pthread.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>

void *tfn(void *paraArg) {
	while(1) {
		printf("child thread ...\n");
		pthread_testcancel();
	}//of while
}//of tfn

int main(void){
	pthread_t tempTid;
	void *tempTret = NULL;
	pthread_create(&tempTid, NULL, tfn, NULL);
	sleep(1);
	pthread_cancel(tempTid);
	pthread_join(tempTid, &tempTret);
	printf("child thread exit code = %ld\n", (long int)tempTret);
	return 0;
}//of main

在这里插入图片描述


五、线程挂起

在进程中,可以使用wait(),waitpid()将进程挂起,以等待某个子进程结束,在线程中采用pthread_join函数,该函数位于函数库pthread.h中,具体形式如下:

int pthread_join(pthread_t thread, void **retval);

参数:
thread:表示被等待的线程id;
retval:用于接收thread线程执行函数的返回值指针,该指针的值与thread线程的终止方式有关:
– 通过return返回:retval存放的是thread线程函数的返回值;
– 其它线程通过系统调用pthread_cancel异常终止,retval存放的是常量PTHREAD_CANCELED;
– 自调用pthread_exit终止,retval存放的是pthread_exit的参数ret_val;
– 若不关心它的终止状态,retval设置为NULL。

#include <pthread.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>

typedef struct {
	int a;
	int b;
} exit_t;
void *tfn(void *paraArg){
	exit_t *tempRet;
	tempRet = malloc(sizeof(exit_t));
	tempRet->a = 100;
	tempRet->b = 300;
	pthread_exit((void *)tempRet);
	return NULL;	
}//of tfn

int main(void){
	pthread_t tempTid;
	exit_t *tempRetval;
	pthread_create(&tempTid, NULL, tfn, NULL);
	pthread_join(tempTid, (void **)&tempRetval);
	printf("a = %d, b = %d\n", tempRetval->a, tempRetval->b);
	return 0;
}//of main

在这里插入图片描述

总结

本次课程主要学习了对于线程的管理,第一次认识到线程这一概念是在操作系统中,但都是概念性的知识,本节课中具体使用代码对一个线程进行创建、终止、退出、挂起等操作,对于线程的认识更加深刻,也进一步理解了线程与进程直接的区别。

参考链接:https://blog.csdn.net/search_129_hr/article/details/124646059

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值