实验七:Linux多线程编程(4课时)
实验目的:掌握线程的概念;熟悉Linux下线程程序编译的过程;掌握多线程程序编写方法。
实验原理:为什么有了进程的概念后,还要再引入线程呢?使用多线程到底有哪些好处?什么的系统应该选用多线程?我们首先必须回答这些问题。
1 多线程概念
使用多线程的理由之一是和进程相比,它是一种非常"节俭"的多任务操作方式。运行于一个进程中的多个线程,它们彼此之间使用相同的地址空间,共享大部分数据,启动一个线程所花费的空间远远小于启动一个进程所花费的空间。
使用多线程的理由之二是线程间方便的通信机制。同一进程下的线程之间共享数据空间,所以一个线程的数据可以直接为其它线程所用,这不仅快捷,而且方便。
2多线程编程函数
Linux系统下的多线程遵循POSIX线程接口,称为pthread。编写Linux下的多线程程序,需要
使用头文件pthread.h,连接时需要使用库libpthread.a。
pthread_t在头文件/usr/include/bits/pthreadtypes.h中定义:
typedef unsigned long int pthread_t; 它是一个线程的标识符。
函数pthread_create用来创建一个线程,它的原型为:
extern int pthread_create((pthread_t *thread, const pthread_attr_t *attr,
linux下的sleep函数void *(*start_routine) (void *), void *arg));
第一个参数为指向线程标识符的指针,第二个参数用来设置线程属性,第三个参数是线程运行函数的起始地址,最后一个参数是运行函数的参数。
函数pthread_join用来等待一个线程的结束。函数原型为:
extern int pthread_join(pthread_t th, void **thread_return);
第一个参数为被等待的线程标识符,第二个参数为一个用户定义的指针,它可以用来存储
被等待线程的返回值。
函数pthread_exit的函数原型为:
extern void pthread_exit(void *retval);
唯一的参数是函数的返回代码,只要pthread_join中的第二个参数thread_return不是NULL,这个值将被传递给 thread_return。
3 修改线程的属性
线程属性结构为pthread_attr_t,它在头文件/usr/include/pthread.h中定义。属性值不能直接设置,须使用相关函数进行操作,初始化的函数为pthread_attr_init,这个函数必须在pthread_create函数之前调用。
设置线程绑定状态的函数为 pthread_attr_setscope,它有两个参数,第一个是指向属性结构的指针,第二个是绑定类型,它有两个取值:PTHREAD_SCOPE_SYSTEM(绑定的)和PTHREAD_SCOPE_PROCESS(非绑定的)。
另外一个可能常用的属性是线程的优先级,它存放在结构sched_param中。用函数pthread_attr_getschedparam和函数 pthread_attr_setschedparam进行存放,一般说来,我们总是先取优先级,对取得的值修改后再存放回去。
4 线程的数据处理
和进程相比,线程的最大优点之一是数据的共享性,各个进程共享父进程处沿袭的数据段,可以方便的获得、修改数据。但这也给多线程编程带来了许多问题。我们必须当心有多个不同的进程访问相同的变量。许多函数是不可重入的,即同时不能运行一个函数的多个拷贝(除非使用不同的数据段)。在函数中声明的静态变量常常带来问题,函数的返回值也会有问题。
互斥锁
互斥锁用来保证一段时间内只有一个线程在执行一段代码。必要性显而易见:假设各个线程向同一个文件顺序写入数据,最后得到的结果一定是灾难性的。
条件变量
互斥锁一个明显的缺点是它只有两种状态:锁定和非锁定。而条件变量通过允许线程阻塞和等待另一个线程发送信号的方法弥补了互斥锁的不足,它常和互斥锁一起使用。使用时,条件变量被用来阻塞一个线程,当条件不满足时,线程往往解开相应的互斥锁并等待条件发生变化。
信号量
信号量既可以作为二值计数器(即0,1),也可以作为资源计数器.
信号量本质上是一个非负的整数计数器,它被用来控制对公共资源的访问。当公共资源增加时,调用函数sem_post()增加信号量。只有当信号量值大于0时,才能使用公共资源,使用后,函数sem_wait()减少信号量。函数sem_trywait()和函数pthread_ mutex_trylock()起同样的作用,它是函数sem_wait()的非阻塞版本。
实验内容:线程函数编译时需要添加特殊编译选项:gcc *.c -lpthread -o
1、 完成教材上thread.c的例子,想一下每次执行时结果相同吗,为什么?
答:每个线程的运行和结束时无序的、独立与并行的。
实验代码:
/* thread.c */
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#define THREAD_NUMBER 3 /*线程数*/
#define REPEAT_NUMBER 5 /*每个线程中的小任务数*/
#define DELAY_TIME_LEVELS 6.0 /*小任务之间的最大时间间隔*/
void *thrd_func(void *arg) //指针好乱,这里看不懂定义了什么,求解释
//定义了一个返回值为指向空类型的指针的函数,该函数的参数为一个指针
{ /* 线程函数例程 */
int thrd_num = (int)arg; //这个是赋值吗?看不懂,求解释
//定义了一个整型参数,取值为arg
int delay_time = 0;
int count = 0;
printf("Thread %d is starting\n", thrd_num);
for (count = 0; count < REPEAT_NUMBER; count++)
{
delay_time = (int)(rand() * DELAY_TIME_LEVELS/(RAND_MAX)) + 1;
printf("\tThread %d: job %d delay = %d\n",thrd_num, count, delay_time);
sleep(delay_time); //暂停?秒 //暂停随机秒
}
//\t 输出一个Tab 占8列
//输出格式 : Thread thrd_num: job count delay = delay_time 回车
printf("Thread %d finished\n", thrd_num);
//输出格式: Thread thrd_num finished 回车
pthread_exit(NULL);
}
int main(void)
{
pthread_t thread[THREAD_NUMBER];
//定义了一个类型为pthread_t的数组,数组元素的个数为3
int no = 0, res;
void * thrd_ret; //这句什么意思?求解释
//定义了一个指针,指向哪里后面的程序里有。
srand(time(NULL)); //这句什么意思? 求解释
//用系统时间计算一个随机数。
for (no = 0; no < THREAD_NUMBER; no++)
{
/* 创建多线程 */
res = pthread_create(&thread[no], NULL, thrd_func, (void*)no); //&thread[no]线程标识符
//pthread_create函数的参数含义请看书。
if (res != 0) //创建线程出错时 res=错误码
{
printf("Create thread %d failed\n", no);
exit(res);//上面的不是退出进程,而是判断pthread_create()函数是否成功执行。
}
}
printf("Create treads success\n Waiting for threads \n");
//如果上面没退出进程,则创建线程成功
for (no = 0; no < THREAD_NUMBER; no++)
{
/* 等待线程结束 */
res = pthread_join(thread[no], &thrd_ret);
// thread[no]线程标识符,此例总共有thread[0],thread[1],thread[2],3个线程 //请看书上pthread_join()函数的参数含义。
if (!res) //res=0时,挂起线程成功
//res=0时,说明pthread_join()函数执行成功。
{
printf("Thread %d joined\n", no);
}
else
{
printf("Thread %d join failed\n", no);
}
}
return 0;
}
2、 完成教材上thread_mutex.c例,查看运行情况。和上例比较有何不同,想一下为什么会出现这种差异?
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论