码迷,mamicode.com
首页 > 编程语言 > 详细

对线程的深入学习(一)

时间:2015-07-30 19:31:08      阅读:146      评论:0      收藏:0      [点我收藏+]

标签:uc

对线程概念的理解:

1. 线程就是程序的执行路线,即进程内部的控制序列,或者说是进程的子任务。
2. 线程,轻量级,不拥有自己独立的内存资源,共享进程的代码区、数据区、堆区(注意没有栈区)、环境变量和命令行参数、文件描述符、信号处理函数、  当前目录、用户ID和组ID等资源。
3. 线程拥有自己独立的栈,因此也有自己独立的局部变量。
4. 一个进程可以同时拥有多个线程,  即同时被系统调度的多条执行路线, 但至少要有一个主线程。

更深入的理解:
5. 线程是进程的一个实体,可作为系统独立调度和分派的基本单位。
6. 线程有不同的状态,系统提供了多种线程控制原语,如创建线程、销毁线程等等。
7. 线程不拥有自己的资源,只拥有从属于进程的全部资源,所有的资源分配都是面向进程的。
8. 一个进程中可以有多个线程并发地运行。 它们可以执行相同的代码,也可以执行不同的代码。
9. 同一个进程的多个线程都在同一个地址空间内活动,因此相对于进程,线程的系统开销小,任务切换快
10. 线程间的数据交换不需要依赖于类似IPC的特殊通信机制, 简单而高效。
11. 每个线程拥有自己独立的线程ID、寄存器信息、函数栈、  错误码和信号掩码。
12. 线程之间存在优先级的差异。

自己的见解:

       进程严格意义上讲只是进程映像(如下图),并不包括程序运行的那个动作,而线程则是程序的执行路线pthread_create的第三个参数就是实现这个动作的。打个比方进程就像是一桌子饭,线程就是吃饭的动作,多个人吃饭就是多线程,饭只有一份,但是每个人都吃到自己的肚子里,肚子就类似线程的临时存储区域(栈),在线程中只有栈是独立的,其他的都是共享进程的。

技术分享

1. 创建线程

int pthread_create (pthread_t* restrict thread,
                    const pthread_attr_t* restrict attr,
                    void* (*start_routine) (void*),
                    void* restrict arg);
      thread - 线程ID,输出参数。pthread_t 即 unsigned long int。
      attr - 线程属性,NULL表示缺省属性。pthread_attr_t可能是整型也可能是结构,因实现而异。
      start_routine - 线程过程函数指针,参数和返回值的类型都是void*。启动线程本质上就是调用一个函数 只不过是在一个独立的线程中调用的,函数返回即线程结束。
      arg - 传递给线程过程函数的参数。线程过程函数的调用者是系统内核,而非用户代码,因此需要在创 建线程时指定参数。
      成功返回0,失败返回错误码。

注意:
    1) restrict: C99引入的编译优化指示符,提高重复解引用同一个指针的效率。(解引用的过程其实就是在内存中查找地址想,做的优化其实质就是访问寄存器里的代替访问内存)
    2) 在pthread.h头文件中声明的函数,通常以直接返回错误码的方式表示失败,而非以错误码设置errno
    3) main函数即主线程,main函数返回即主线程结束,主线程结束即进程结束,进程一但结束其所有的线程即结束。(子进程不一定结束,可能成为孤儿)
    4) 应设法保证在线程过程函数执行期间,其参数所指向的目标持久有效。                                                                                                               
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <pthread.h>

void* thread_proc (void* arg) {
	printf ("%lu线程:%s\n", pthread_self (), (char*)arg);
	return NULL;
}

int main (void) {
	pthread_t tid;
	int error = pthread_create (&tid, NULL, thread_proc,
		"我是快乐的子线程!");
	if (error) {
		fprintf (stderr, "pthread_create: %s\n", strerror (error));
		return -1;
	}

	printf ("%lu线程:我是主线程,创建了%lu线程。\n", pthread_self (),tid);//pthread_self () 自己的tid
	sleep (1);
	return 0;
}

技术分享

     1. sleep在这里的作用: 因为 主线程和子线程的执行顺序是不一定的,这里通过sleep让主线程等一会儿,让子线程不至于还没结束主线程就结束了

      2. 如果去掉sleep这行我们偶尔会出现子进程被打印两次的结果,原因是缓冲区的问题,我们只要加上setbuf(stdout,NULL);(关闭输出缓冲区) 就好了。因为缓冲区在进程关闭的时候刷新一次,刷新缓冲区实质上是两个步骤,第一步把缓冲区的内容显示出来,第二步就是清空,子线程打印两次的情况就是因为在第一二步骤之间切换了下线程,转去执行了一次子线程,这样就导致缓冲区又刷新了一次。

      3. 去掉sleep当然也会遇到不打印子进程的情况,这完全取决于cpu的调度

//线程并发:开20个线程,每一列代表一个,打印1-500的数字
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <pthread.h>

void* thread_proc (void* arg) {
	size_t i;
	for (i = 0; i < 500; i++) {
		printf ("%*d\n", ((size_t)arg + 1) * 4, i + 1); //*表示跳过的意思,rag就是0-19号进程,这行意义就是                                                                 //让不同的线程之间有空格
		usleep (50000);//50ms,sleep的参数是秒
	}

	return NULL;
}

int main (void) {
	pthread_t tids[20];//20个线程

	size_t i;
	for (i = 0; i < sizeof (tids) / sizeof (tids[0]); i++) {
		int error = pthread_create (&tids[i], NULL, thread_proc, (void*)i);
		if (error) {
			fprintf (stderr, "pthread_create: %s\n", strerror (error));
			return -1;
		}
	}

	for (i = 0; i < sizeof (tids) / sizeof (tids[0]); i++) {
		int error = pthread_join (tids[i], NULL);
		if (error) {
			fprintf (stderr, "pthread_join: %s\n", strerror (error));
			return -1;
		}
	}

	return 0;
}
技术分享





版权声明:本文为博主原创文章,未经博主允许不得转载。

对线程的深入学习(一)

标签:uc

原文地址:http://blog.csdn.net/meetings/article/details/47148367

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!