进程管理实验——POSIX下线程控制(二)

实验目的

1、通过观察、分析实验现象,深入理解线程及线程在调度执行和内存空间等方面的特点,并掌握线程与进程的区别。

2、掌握在POSIX 规范中pthread_create() 函数的功能和使用方法。


实验前准备

pthread_create()函数:

函数简介

  pthread_create是UNIX环境创建线程函数

头文件

  #include

函数声明

  int pthread_create(pthread_t *restrict tidp, const pthread_attr_t *restrict_attr, void*(*start_rtn)(void*), void *restrict arg);

返回值

  若成功则返回0,否则返回出错编号

参数

  第一个参数为指向线程标识符的指针。

  第二个参数用来设置线程属性。

  第三个参数是线程运行函数的地址。

  最后一个参数是运行函数的参数。

注意

  在编译时注意加上-lpthread参数,以调用静态链接库。因为pthread并非Linux系统的默认库。 


实验程序:(已在Ubuntu 14.04下完美运行)

#include  
#include 
#include  
#include 
#include  

#define MAX_THREAD 3 /* 线程的个数 */
unsigned long long main_counter, counter[MAX_THREAD]; /* unsigned long long是比long还长的整数 */
void *thread_worker(void *); 

void *thread_worker(void *p) { 
	int thread_num; 
	/* 在这里填写代码,把main中的i的值赋给thread_num */ 
	thread_num = *((int *)p);
	/* 无限循环 */
	for(;;) { 
		counter[thread_num]++; /* 本线程的counter加一 */
 		main_counter++; /* 主counter 加一 */
 	} 
}

int main(int argc, char* argv[]) { 
	int i, rtn, ch; 
	pthread_t pthread_id[MAX_THREAD] = {0}; /* 存放每个线程的id */ 

	for (i = 0; i < MAX_THREAD; i++) { 
		/* 在这里填写代码,用pthread_create建一个普通的线程,
		 *线程id存入pthread_id[i].
		 */
		/*线程执行的函数是thread_worker,并i作为参数传递给线程 */
		rtn = pthread_create(&pthread_id[i], NULL, (void *)thread_worker, &i); 
	}
	/* 用户按一次回车执行下面的循环体一次。按q退出 */
	do { 
		unsigned long long sum = 0;
		/* 求所有线程的counter的和 */
		for (i = 0; i < MAX_THREAD; i++) { 
			sum += counter[i]; 
			printf("%llu ", counter[i]); 
		}
	 	printf("%llu/%llu", main_counter, sum); 
	} while ((ch = getchar()) != 'q'); 

	return 0; 
} 

实验过程:

运行程序。开另一个终端窗口,运行“ps aux”命令,看看thread 的运行情况,注意查看thread 的CPU 占用率,并记录下这个结果。

进程管理实验——POSIX下线程控制(二)_第1张图片

 每行前三个数是每个线程的counter,第四个数是main_counter,最后一个数是三个线程的counter总和。

进程管理实验——POSIX下线程控制(二)_第2张图片

这个程序运行时,在这时CPU占用达到了296!

实验问题:

1. 你最初认为前三列数会相等吗?最后一列斜杠两边的数字是相等,还是大于或者小于关系?

我最初认为前三列数不相等,最后一列斜杠两边的数字是相等的。
2. 最后的结果如你所料吗?有什么特点?试对原因进行分析。

结果:前三列数不相等,main_counter值在小于sum值。

分析:main_counter是一个共享变量,三个线程共同抢占运行thread_worker()函数。比如第一个线程运行counter[thread_num]++;后,正准备运行main_counter++,结果不巧的是,第二个线程把main_counter这个共享资源抢夺了,就在第二个线程准备运行main_counter++时,第三个线程势力比较大,把main_counter抢夺了,这样,经过一番激烈的争夺,第一和第二个线程没有来的急把main_counter++自增1的值赋值给main_counter,main_counter++就被第三个线程执行并赋值了。本来按理想情况推断,每一次counter[thread_num]++都伴随着main_counter++,却不料,main_counter很受欢迎,被三个线程抢夺,最终赋值只执行了一次,所以会发生main_counter值比sum值小的情况。
3. thread 的CPU 占用率是多少?为什么会这样?

cpu占用率296,因为线程是无限死循环,所以占用率高。
4. thread_worker()内是死循环,它是怎么退出的?你认为这样退出好吗?

输入q,这样退出不好。

如果输入q,所有线程都结束。线程终止的两种方式是:执行return或pthread_exit()。

       执行return:在主线程中,如果main函数返回或调用了exit函数退出主线程,则整个进程中的所有线程也将终止,因此在主线程中不能过早的从main函数返回,可调用pthread_join()函数同步。

       执行pthread_exit():另一种情况是如果主线程调用pthread_exit()函数,则仅仅是主线程消亡,进程不会结束,进程内的其他线程也不会终止,直到所有线程结束,进程才会结束。

你可能感兴趣的:(杂项)