栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

线程-线程函数接口-守护进程的创建

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

线程-线程函数接口-守护进程的创建

目录

一,守护进程

2.创建守护进程的步骤:

二,线程-重点

1.概念

2.进程和线程的区别

3.线程资源

三,线程函数

1.线程创建

2.线程退出与线程回收

3.线程同步(信号量)

4.线程互斥与线程条件变量

1.线程互斥

2.线程条件变量


一,守护进程

1.特点:守护进程是后台进程,它的生命周期比较长,从系统启动时开启,在系统关闭时结束;它是脱离控制终端且周期执行的进程。

2.创建守护进程的步骤:

(1)使用fork函数,创建子进程,让父进程退出,使子进程成为孤儿进程(后台进程);

(2)使用setsid函数,在子进程中创建新会话,让子进程成为会话组组长,让子进程完全脱离终端;

(3)使用chdir函数,改变进程运行路径为根目录,因为守护进程的路径不能被删除或卸载;

(4)使用umask函数,重设文件权限掩码,目的是增大守护进程的权限;

(5)使用close函数关闭文件描述符,将不需要的文件关闭。

代码演示:

#include 
#include 
#include 
#include 
#include 
#include 

int main(int argc, char const *argv[])
{
    pid_t pid;
    if((pid = fork()) < 0)
    {
    perror("fork err");
    return -1;
    }else if(pid == 0)
{
    int i;
    setsid(); //在子进程中创建会话
    chdir("/"); //改变当前路径为根目录
    umask(0); //重设文件权限掩码
    for(i = 0;i < 3;i++)
    {
        close(i); //关闭文件描述符
    }
    //守护进程文件路径
    int fd = open("/tmp/error.log",O_WRONLY|O_CREAT|O_APPEND,0777);
    while(1)
    {
        write(fd,"hello",5);
        sleep(1);
    }
}
else
{
    exit(0);
}
    return 0;
}

    执行程序后,可以在目录/temp下找到error.log文件。

二,线程-重点

1.概念

    线程相当于一个轻量级的进程,可以提高系统的性能;在Linux系统中,同样使用结构体task_struct来描述一个线程;线程和进程都参加统一的调度。

    在同一个进程中创建的线程共享该进程的地址空间。

2.进程和线程的区别

    共同点:都为操作系统提供了并发执行的能力;

    不同点:(1)线程是系统调度的最小单位;进程是资源分配的最小单位;

(2)同一个进程创建的多个线程共享进程的资源;进程的地址空间相互独立;

(3)线程通信相对简单,可通过全局变量实现,但是需要考虑临界资源访问的问题;进程通信比较复杂,需要借助进程间的通信机制(3G-4G的内核空间);

(4)线程安全性较差,当进程结束时会导致所有的线程退出,一个线程的结束可能会影响到其他线程;进程相对安全。

3.线程资源

    共享的资源:可执行的指令,静态数据,进程中打开的文件描述符,信号处理函数,当前工作目录,用户ID,用户组ID。

    私有的资源:线程ID(TID),PC(程序计数器)和相关寄存器,堆栈,错误码,信号掩码,优先级,执行状态和属性。

三,线程函数

1.线程创建

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

功能:创建线程;

参数:thread->线程标识;

attr->线程属性,常设置为默认属性NULL;

start_toutine->函数名,代表线程函数,函数的参数应为void *arg;

arg->用来给线程函数传参;

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

代码演示:

#include 
#include 
#include 

//线程函数
void *handler(void *arg)
{
    printf("in threadn");
}
int main(int argc, char const *argv[])
{
    //定义pthread_t类型的tid
    pthread_t tid;
    //判断,返回值不为0则创建失败
    if(pthread_create(&tid,NULL,handler,NULL) != 0)
    {
        perror("thread create err");
        return -1;
    }
    printf("in mainn");
    //不一定会进入线程,所以使用循环保证线程运行
    while(1);
    return 0;
}

2.线程退出与线程回收

(1) 函数:int pthread_exit(void *value_ptr);

功能:执行线程退出的功能;

参数:value_ptr->线程退出时返回的值,一般设置为NULL;

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

(2) 函数:int pthread_join(pthread_t thread,void **value_ptr);

功能:用于等待一个指定的线程结束;

参数:thread->创建的线程对象;

           value_ptr->指针*value_ptr指向线程返回的参数,一般设置为NULL;

返回值:成功->0;失败->错误码。

代码演示:

#include 
#include 
#include 

void *handler(void *arg)
{
    printf("in threadn");
	//pthread_exit(NULL);//结束线程
	pthread_exit("hello");
}
int main(int argc, char const *argv[])
{
    pthread_t tid;
    if(pthread_create(&tid,NULL,handler,NULL) != 0)
    {
        perror("thread create err");
        return -1;
    }
	
    printf("in mainn");
    //接收线程返回的参数hello
	void *ch;
	pthread_join(th,&ch);
	printf("%sn",(char *)ch);

	//pthread_join(th,NULL);//回收线程资源
    return 0;
}

3.线程同步(信号量)

(1)概念: 同步(synchronization)指的是多个任务(线程)按照约定的顺序相互配合完成一件事情;

(2)信号量:通过信号量实现同步操作;由信号量来决定线程是继续运行还是阻塞等待;

    信号量代表某一类资源,其值表示系统中该资源的数量;

    信号量是一个受保护的变量,只能通过三种操作来访问:初始化、P操作(申请资源)、V操作(释放资源);

    信号量的值为非负整数。

(3)函数接口

①int  sem_init(sem_t *sem,  int pshared,  unsigned int value)   

功能:初始化信号量;

参数:sem->初始化的信号量对象;

     pshared->信号量共享的范围  (0: 线程间使用   非0:1进程间使用);

      value->信号量初值;

返回值:成功为0,失败为-1;

sem_t sem;
if(sem_init(&sem,0,0) < 0)
	{
		perror("sem init err");
		return -1;
	}

②int  sem_wait(sem_t *sem)    

功能:申请资源,P操作;

参数:sem->信号量对象;

返回值:成功为0,失败为-1;

注:此函数执行过程,执行到wait,先对信号量进行减1,若减完的信号量的值大于等于0,表示有资源可以用,则继续执行;当信号量的值小于0时,表示没有资源可以使用,函数阻塞。

③int  sem_post(sem_t *sem) 

功能:释放资源,V操作; 

参数:sem->信号量对象;

返回值:成功为0,失败为-1;

代码演示:

#include 
#include 
#include 
#include 
#include 

char ch[32] = "";
sem_t sem;
void *handler(void *arg)
{
	while(1)
	{
		//给信号量 -1
		sem_wait(&sem);

		if((strcmp(ch,"quit") == 0))
		{
			pthread_exit(NULL);
		}
		printf("threadn");
		printf("output:%sn",(char *)arg);
	
	}
}

int main(int argc, char const *argv[])
{
	//创建线程
    pthread_t tid;
	//给线程函数传递参数ch,先强转为void *类型
   	if(pthread_create(&tid,NULL,handler,(void *)&ch) != 0)
    {
        perror("thread create err");
       	return -1;
    }
	//初始化信号量(信号量对象,0->线程间使用,信号量初值)
	if(sem_init(&sem,0,0) < 0)
	{
		perror("sem init err");
		return -1;
	}
	while(1)
	{
		scanf("%s",ch);
		//信号量+1
		sem_post(&sem);
		if(strcmp(ch,"quit")==0)
		break;
	}
	pthread_join(tid,NULL);
	printf("mainn");
    return 0;
}

    执行结果:输入一串字符串后,信号量先增加1,如果字符串不是“quit”,则线程中的wait判断信号量不为0,字符串也不为“quit”,就输出字符串,然后如果线程继续循环,wait检测到信号量为0时,将会继续运行主进程的循环,继续输入字符串,信号量再+1。

4.线程互斥与线程条件变量

1.线程互斥

1.相关概念

(1)临界资源:一次仅允许一个进程所使用的资源;

(2)临界区:指的是一个访问共享资源的程序片段;

(3)互斥:多个线程在访问临界资源时,同一时间只能被一个线程访问;

(4)互斥锁:通过互斥锁可以实现互斥机制,使用互斥锁的目的是用来保护临界资源,每个临界资源都应该由一个互斥锁来保护,线程必须先获得互斥锁才能访问临界资源,访问完资源后释放该锁。如果无法获得锁,线程会阻塞直到获得锁为止。

2.函数接口

(1)int pthread_mutex_init(pthread_mutex_t *mutex, pthread_mutexattr_t *attr)

功能:初始化互斥锁;

参数:mutex ->互斥锁,用pthread_mutex_t来定义该参数;

pthread_mutex_t lock;

attr ->互斥锁属性 ,一般设置为NULL;

返回值:成功为0,失败为-1;

(2)int pthread_mutex_lock(pthread_mutex_t *mutex)

功能:申请互斥锁;

参数:mutex->互斥锁;

//初始化锁
pthread_nutex_t lock;
if(pthread_mutex_init(&lock,NULL)<0)
    {
        perror("mutex init err");
        return -1;
    }
//上锁
pthread_mutex_lock(&lock);

返回值:成功为0,失败为-1;

注:pthread_mutex_lock和pthread_mutex_trylock区别:pthread_mutex_lock申请不到锁是会阻塞函数的;pthread_mutex_trylock不阻塞,如果申请不到锁会立刻返回。

(3)int pthread_mutex_unlock(pthread_mutex_t *mutex)

功能:释放互斥锁;

参数:mutex->互斥锁;

//初始化锁
pthread_nutex_t lock;
if(pthread_mutex_init(&lock,NULL)<0)
    {
        perror("mutex init err");
        return -1;
    }
//上锁
pthread_mutex_lock(&lock);
//解锁
pthread_mutex_unlock(&lock);

返回值:成功为0,失败为-1。

(4)int pthread_mutex_destroy(pthread_mutex_t *mutex)

功能:销毁互斥锁;

参数:mutex->互斥锁;

代码演示:

#include 
#include 
#include 

//互斥锁参数
pthread_mutex_t lock;

int a[10] = {0,1,2,3,4,5,6,7,8,9};
int i;
//线程函数
void *handler_swap(void *arg)
{
    int temp;
    while(1)
    {
        //上锁
        pthread_mutex_lock(&lock);
        for(i = 0;i < 5;i++)
        {
            temp = a[i];
            a[i] = a[9-i];
            a[9-i] = temp;
        }
        //解锁
        pthread_mutex_unlock(&lock);
    }
}

//线程函数
void *handler_printf(void *arg)
{
    while(1)
    {
        //上锁
        pthread_mutex_lock(&lock);
        for(i = 0;i < 9;i++)
        {
            printf("%d ",a[i]);
        }
        putchar(10);
        //解锁
        pthread_mutex_unlock(&lock);
        sleep(1);
    }
}
int main(int argc, const char *argv[])
{
    //创建两个线程
    pthread_t tid1,tid2;
    if(pthread_create(&tid1,NULL,handler_swap,NULL)!=0)
    {
        perror("thread create err");
        return -1;
    }
    if(pthread_create(&tid2,NULL,handler_printf,NULL)!=0)
    {
        perror("thread create err");
        return -1;
    }
    
    //初始化锁
    if(pthread_mutex_init(&lock,NULL)<0)
    {
        perror("mutex init err");
        return -1;
    }

    //回收线程资源
    pthread_join(tid1,NULL);
    pthread_join(tid2,NULL);
    return 0;
}

    执行结果为:在终端中循环正序输出0到9,或9到0,不能确定输出的次数,但是不会打乱一次输出中的顺序。

2.线程条件变量 条件变量需要与 互斥锁搭配使用,实现 同步机制;
(1)int pthread_cond_init (pthread_cond_t *restrict cond,const pthread_condattr_t *restrict attr);
功能: 初始化 条件变量; 参数:cond->是一个指向结构pthread_cond_t 的指针;
pthread_cond_t cond;
pthread_cond_init(&cond,NULL);

restrict attr->是一个指向结构pthread_condattr_t的指针,一般设为NULL;

返回值:成功为0,失败为非0。

初始化时,通过判断返回值是否小于0,来确定是否初始化成功,小于0则初始化失败

(2)int pthread_cond_wait(pthread_cond_t *restrict cond,pthread_mutex_t *restrict mutex);

功能: 等待信号 的产生; 参数:restrict cond->要等待的条件; restrict mutex->对应的锁; 返回值:成功为0 ,失败不为0。 注:当没有条件产生时->函数阻塞,锁解开; 等待到条件产生->函数结束阻塞,同时上锁。
pthread_cond_wait(&cond,&lock);

(3)int pthread_cond_signal(pthread_cond_t *cond);

功能:给条件变量发送信号, 产生信号; 参数:cond->条件变量值;
pthread_cond_signal(&cond);

返回值:成功为0,失败为非0;

注:必须等待pthread_cond_wait函数先执行,再产生条件信号。

    此函数和pthread_cond_broadcast区别是:

pthread_cond_broadcast函数相当于是广播,会将所有等待此条件的线程唤;

pthread_cond_signal只能唤醒单个等待此条件的线程。

(4)int pthread_cond_destroy (pthread_cond_t *cond);
功能:将条件变量销毁; 参数:cond->条件变量值; 返回值:成功为 0 ,失败为非0; 代码演示:
#include 
#include 
#include 

//函数pthread_mutex_init()中的参数
pthread_mutex_t lock;
//函数pthread_cond_init()中的参数
pthread_cond_t cond;
int money = 0;

void *handler_get(void *arg)
{
    while(1)
    {
        pthread_mutex_lock(&lock);//上锁
        if(money < 100)
        {
            //当没有条件cond产生时阻塞,同时将锁打开;
            //等待到条件产生时,函数立即返回同时进行上锁;
            pthread_cond_wait(&cond,&lock);
        }
        if(money >= 100)
        {
            money -= 100;
            printf("money:%dn",money);
        }
        pthread_mutex_unlock(&lock);//解锁
    }
}

void *handler_save(void *arg)
{
    while(1)
    {
        sleep(1);//睡眠一秒确保get线程先执行
        pthread_mutex_lock(&lock);//上锁
        scanf("%d",&money);
        pthread_mutex_unlock(&lock);//解锁

        pthread_cond_signal(&cond);//产生cond条件(信号);
    }
}
int main(int argc, char const *argv[])
{
    pthread_t tid1,tid2;
    //创建线程:tid->pthread_t,NULL,线程函数名,函数参数
    if(pthread_create(&tid1,NULL,handler_get,NULL)!=0)
    {
        perror("create tid1 err");
        return -1;
    }
    if(pthread_create(&tid2,NULL,handler_save,NULL)!=0)
    {
        perror("create tid2 err");
        return -1;
    }
    
    //初始化锁
    //参数:取地址-定义的pthread_mutex_t lock,状态NULL
    //返回值小于0时,创建失败
    if(pthread_mutex_init(&lock,NULL) < 0)
    {
        perror("mutex init err");
        return -1;
    }

    //初始化条件变量
    //参数:取地址-定义的pthread_cond_t cond,状态NULL
    //返回值小于0时,创建失败
    if(pthread_cond_init(&cond,NULL) < 0)
    {
        perror("cond init err");
        return -1;
    }

    //回收线程资源
    pthread_join(tid1,NULL);
    pthread_join(tid2,NULL);

    return 0;
}

执行结果:

如果本文中存在概念错误或代码错误的情况,请批评指正。

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/1031554.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号