linux——线程

什么是线程

线程:也称轻量级进程(Lightweight Process , LWP),是程序执行流的最小单元。而多线程就是指,在一个进程中有多个执行流,在同时执行。

在一个程序里的一个执行路线叫做线程,线程是一个进程内部的控制序列。一个进程可以拥有多个线程,但是至少都有一个执行线程(单线程进程),线程的执行粒度比进程更细致,线程资源共享。

Linux线程

在Linux中——并不存在真正的线程,Linux的线程是使用进程模拟的。我们在Linux系统中,线程的创建是在内核外进行的,有POSIX提供的线程库实现。因此链接这些线程函数库时要使用编译器命令的”-lpthread”选项。Linux下的线程也叫做轻量级进程(LWP)。

在Linux中——新建的线程并不是在原先的进程中,而是系统通过 一个系统调用clone()。该系统copy了一个和原先进程完全一样的进程,并在这个进程中执行线程函数。不过这个copy过程和fork不一样。 copy后的进程和原先的进程共享了所有的变量,运行环境。所以线程是共享全局变量和环境的。

以上线程创建函数在libpthread.so,故编译的时候 gcc –o 程序名 –lpthread 文件名
创建线程

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

void *func(void *arg)
{

	int n = *(int*)(arg);

	while (1)
	{
		printf("child thread n = %d\n", n);
		sleep(1);
	}
}


int main()
{
	int n = 5;

	pthread_t tid;
	int ret;
	ret = pthread_create(&tid, NULL, func, (void*)&n);

	if (ret != 0)
	{
		fprintf(stderr, "pthread_create:%s\n", strerror(ret));
		exit(-1);
	}

	while (1)
	{
		printf("main thread\n");
		sleep(1);
	}
}
创建线程所要的参数
#include <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一个函数地址,线程启动后执行的函数;
arg传给执行的函数的参数
返回值:成功返回0,失败返回错误码。

等待线程结束
有的时候,我们需要等待线程结束,此时才能继续执行后面的事情。如果不等待线程结束,则主线程(main函数)会直接往下执行导致程序退出,线程函数都无法得到执行。
注意:已经退出的线程,其空间没有被释放,仍然在进程的地址空间中。创建新的线程不会复用刚才退出线程的空间地址。

pthread库中等待线程结束的函数是pthread_join,它的声明如下:

功能:作用是使调用者阻塞,直至指定的线程退出。
原型:
#include <pthread.h>
int pthread_join(pthread_t thread, void **retval);

pthread_t thread:        线程的tid
void **retval:          接收退出线程传递出的返回值
返回值:成功返回0,失败返回错误号

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

void * func(void* arg)
{
	while (1)
	{
		printf("I am still alive.....\n");
		sleep(1);
	}
}

int main()
{

	pthread_t tid1;
	pthread_create(&tid1, NULL, func, NULL);

	sleep(2);
	printf("Main thread ends and all threads end!\n");

	//main thread quit
	exit(0);
	return 0;
}

注意:
调用该函数的线程将挂起等待,直到id为thread的线程终止。thread线程以不同的方法终止,通过pthread_join得到的终止状态是不同的,

如果thread线程通过return返回,retval所指向的单元里存放的是thread线程函数的返回值。
如果thread线程被别的线程调用pthread_cancel异常终止掉,retval所指向的单元里存放的是常数PTHREAD_CANCELED。
如果thread线程是自己调用pthread_exit终止的,retval所指向的单元存放的是传给pthread_exit的参数。
线程分离
功能:使线程ID为tid的线程处于分离状态
原型:

#include <pthread.h>
int pthread_detach(pthread_t tid);

pthread_t tid : 分离线程的tid
返回值 : 成功返回0, 失败返回错误号。

一般情况下, 线程终止后, 其终止状态一直保留到其它线程调用pthread_join获取它的状态为止。但是线程也可以被置为detach状态, 这样的线程一旦终止就立刻回收它占用的所有资源, 而不保留终止状态。不能对一个已经处于detach状态的线程调用pthread_join, 这样的调用将返回EINVAL。如果已经对一个线程调用了pthread_detach就不能再调用pthread_join了。
通常情况下,若创建一个线程不关心它的返回值, 也不想使用pthread_join来回收(调用pthread_join的进程会阻塞),就可以使用pthread_detach, 将该线程的状态设置为分离态, 使线程结束后, 立即被系统回收。
有两种方式创建分离线程
(1)在线程创建时将其属性设为分离状态(detached);
(2)在线程创建后将其属性设为分离的(detached)。

pthread_detach函数的作用

程序在创建时默认的状态是joinable, 如果一个线程结束运行但没有被join,则它的状态类似于进程中的Zombie Process(僵尸进程),即还有一部分资源没有被回收(退出状态码),所以创建线程者应该pthread_join来等待线程运行结束,并可得到线程的退出代码,回收其资源(类似于wait,waitpid),这样不会导致系统越用越慢的现象

#include <stdio.h>
#include <pthread.h>
#include <string.h>

void *th_run(void *arg)
{
	int n = 3;
	while (n--)
	{
		printf("thread run\n");
		sleep(1);
	}
}

int main()
{
	pthread_t pth;

	pthread_create(&pth, NULL, th_run, NULL);
	pthread_detach(pth);

	sleep(2);

	int status;
	int err = pthread_join(pth, (void *)&status);
	if (err)
	{
		printf("error info[%s]\n", strerror(err));
	}
	else
	{
		printf("thread exit %d\n", status);
	}

	return 0;
}

线程终止
有三个方法可以终止线程:
(1) 线程只是从启动例程中返回,返回值是线程的退出码;
(2) 线程可以被同一例程中的其他线程调用pthread_cancel取消;
(3) 线程调用pthread_exit。

#include <pthread.h>
void pthread_exit(void *rval_ptr);

rval_ptr是一个无类型指针,与传递给启动例程的单个参数类似,进程中的其他线程可以通过调用pthread_join函数访问到这个指针;

#include <pthread.h>
int pthread_join(pthread_t thread, void **rval_ptr);
ret - 成功返回0 否则返回错误编号

注意和exit函数的区别,任何线程里exit导致进程退出,其他线程未工作结束,主线程退出时不能return或exit。需要注意,pthread_exit或者return返回的指针所指向的内存单元必须是全局的或者是用malloc分配的,不能在线程函数的栈上分配,因为当其它线程得到这个返回指针时线程函数已经退出了。
线程取消
功能:调用线程终止同进程中,其他的线程,调用该方法后,被终止的线程并不一定立马被终止,只有在下次系统调用或调用了pthread_testcancel()方法后,才真正终止线程

原型:
#include <pthread.h>
int pthread_cancel(pthread_t tid);

返回值:
ret-成功返回0 失败返回错误码

进程和线程的区别

线程和进程的区别和联系,简述什么是"线程安全"?

线程是指进程内的一个执行单元,也是进程内的可调度实体。
与进程的区别:
(1)地址空间:进程内的一个执行单元,进程至少一个线程,他们共享进程的地址空间,而进程有自己独立的地址空间
(2)资源拥有:进程是资源分配和拥有的单位,同一个进程内的线程共享进程资源
(3)线程是处理器调度的基本单位,但进程不是
(4)二者皆可并发执行

线程安全就是说多线程访问同一代码,不会产生不确定的结果。编写线程安全的代码是低依靠线程同步。

线程与进程的比较

  1. 调度。
    在传统的操作系统中,拥有资源和独立调度的基本单位都是进程。
    在引入线程的操作系统中,线程是独立调度的基本单位,进程是资源拥有的基本单位。
    在同一进程中,线程的切换不会引起进程切换。
    在不同进程中进行线程切换,如从一个进程内的线程切换到另一个进程中的线程时,会引起进程切换。

  2. 拥有资源。
    不论是传统操作系统还是设有线程的操作系统,进程都是拥有资源的基本单位,
    而线程不拥有系统资源(也有一点必不可少的资源),但线程可以访问其隶属进程的系统资源。

  3. 并发性。
    在引入线程的操作系统中,不仅进程之间可以并发执行,而且多个线程之间也可以并发执行,
    从而使操作系统具有更好的并发性,提高了系统的吞吐量。

  4. 系统开销。
    由于创建或撤销进程时,系统都要为之分配或回收资源,如内存空间、 I/O设备等,
    因此操作系统所付出的开销远大于创建或撤销线程时的开销。
    类似地,在进行进程切换时,涉及当前执行进程CPU环境的保存及新调度到进程CPU环境的设置,
    而线程切换时只需保存和设置少量寄存器内容,开销很小。
    此外,由于同一进程内的多个线程共享进程的地址空间,
    因此,这些线程之间的同步与通信非常容易实现,甚至无需操作系统的干预。

  5. 地址空间和其他资源(如打开的文件):
    进程的地址空间之间互相独立,同一进程的各线程间共享进程的资源,某进程内的线程对于其他进程不可见。

  6. 通信方面:
    进程间通信(IPC)需要进程间通过共享内存、管道、信号、socket等方式来实现,
    而线程间可以直接读/写进程数据段(如全局变量)来进行通信,
    当然都要自己去控制数据的一致性(同步或互斥)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值