linux线程

1.线程与进程的区别及优缺点

        线程的概念解释:线程是参与系统调度的最小单位。 它被包含在进程之中, 是进程中的实际运行单位。一个线程指的是进程中一个单一顺序的控制流(或者说是执行路线、执行流), 一个进程中可以创建多个线程, 多个线程实现并发运行, 每个线程执行不同的任务。 譬如某应用程序设计了两个需要并发运行的任务 task1 task2,可将两个不同的任务分别放置在两个线程中。

线程的特点:main是主线程的入口任何一个进程都包含一个主线程, 只有主线程的进程称为单线程进程。线程是进程中的一部分,而进程是线程的容器。 主线程的重要性体现在两方面:其它新的线程(也就是子线程)是由主线程创建的;主线程通常会在最后结束运行, 执行各种清理工作,譬如回收各个子线程

进程有独立的空间,崩溃情况下,不会对其他进程影响   线程有自己的堆栈和空间但无地址空间,多进程的程序要比多线程的程序健壮,但是进程切换消耗的资源大;  同一进程中的地址空间由多个线程空间共享。

使用多线程的理由之一:

在linux系统下,启动一个新的进程必须分配给他独立的地址空间,建立诸多的数据表来维护它的代码段、数据段和堆栈段。而线程间彼此之间使用相同的地址空间,共享大部分数据。而且启动一个线程的时间远小于启动一个进程的空间,线程间切换时间的时间远远小于进程间切换的时间。

使用多线程的理由之二:

        线程间方便的通信机制。对不同进程来说,它们具有独立的数据空间,要进行数据的传递只能通过通信的方式进行,这种方式不仅费时,而且很不方便。线程则不然,由于同一进程下的线程之间共享数据空间,所以一个线程的数据可以直接为其它线程所用,这不仅快捷,而方便。当然,数据的共享也带来其他一些问题,有的变量不能同时被两个线程所修改,有的子程序中声明为static的数据更有可能给多线程程序带来灾难性的打击,这些正是编写多线程程序时最需要注意的地方。

除了以上所说的优点外,不和进程比较,多线程程序作为一种多任务、并发的工作方式,当然有以下的优点:

·提高应用程序响应。这对图形界面的程序尤其有意义,当一个操作耗时很长时,整个系统都会等待这个操作,此时程序不会响应键盘、鼠标、菜单的操作,而使用多线程技术,将耗时长的操作(timeconsuming)置于一个新的线程,可以避免这种尴尬的情况

·使多CPU系统更加有效。操作系统会保证当线程数不大于CPU数目时,不同的线程运行于不同的CPU上。

·改善程序结构。一个既长又复杂的进程可以考虑分为多个线程,成为几个独立或半独立的运行部分,这样的程序会利于理解和修改。

1.1 补充线程与进程之间的关系:


    1,一个进程的所有线程都共享该进程获得的资源。
    2,各线程有属于自己的一小部分资源,就是栈空间,保存其运行状态和局部自动变量的。
    3,在线程中malloc等申请的空间都是占的进程的资源,即堆资源。
 

2.编程实战

2.0线程的创建

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

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

void *func1(void *arg)
{
	printf("t1:%ld thread is create\n",(unsigned long)pthread_self());
	printf("t1:param is %d\n",*((int *)arg));


}

int main()
{
	int ret;
	int param = 100;
	pthread_t t1;

	ret = pthread_create(&t1, NULL, func1,(void *)&param);//线程创建api *param为入口,可有可无
	if(ret == 0){
		printf("main:create t1 success\n");
	}

	printf("main:%ld\n",(unsigned long)pthread_self());//线程id打印

	pthread_join(t1,NULL);//线程等待

	return 0;
}

2.1线程间共享内存的验证

        主线程创建两个子线程fun1、fun2  ,主线程、两个线程间会有竞争,且他们执行顺序不固定。

共同访问g_data
代码实践:
#include <unistd.h>
#include <stdio.h>
#include <pthread.h>
#include <stdlib.h>
int g_data = 0;
void *func1(void *arg)
{
    printf("t1: %ld t1 thred is create ",(unsigned long)pthread_self());
    printf("t1: param is %d\n",*((int *)arg));
    while(1){printf("t1 g_data: %d\n",g_data++);
           sleep(1);}
}
void *func2(void *arg)
{
    printf("t2: %ld t1 thred is create ",(unsigned long)pthread_self());
    printf("t2: param is %d\n",*((int *)arg));

    while(1){printf("t2 g_data: %d\n",g_data++);
        sleep(1);}
}
int main()
{
    int ret;
    int param = 100;
    pthread_t t1,t2;
    char  *pret = NULL;
    ret = pthread_create(&t1,NULL,func1,(void *)&param); 
    if(ret == 0){

        printf(" main: create t1 success\n");
    }

    ret = pthread_create(&t1,NULL,func2,(void *)&param);//第三个参数为默认入口 
    if(ret == 0){
        printf(" main: create t2 success\n");
    }
    printf("main: %ld  thread is create \n",(unsigned long)pthread_self());

    while(1){printf("main g_data: %d\n",g_data++);
        sleep(1);}
    pthread_join(t1,(void **)&pret);//线程等待

    pthread_join(t2,(void **)&pret);//线程等待
   printf("main :t1 quit pret: %s",pret);
   return 0;
}

程序执行结果:

 2.2线程互斥锁操作

#include <stdio.h>
#include <pthread.h>
#include <unistd.h>
 
int g_data = 0;
 
/*互斥锁*/
pthread_mutex_t lock;
 
/*t1线程*/
void *func1(void *arg)
{
 
 
     while(1)
     {
           /*加锁*/
           pthread_mutex_lock(&lock);
 
           printf("t1 = %d\n",g_data++);
 
           /*解锁*/
           pthread_mutex_unlock(&lock);
 
           /*sleep1秒让t2线程能拿到锁*/
           sleep(1);
     }
 
 
 
}
 
/*t2线程*/
void *func2(void *arg)
{
           /*如果在while里面加锁,会一直加锁,但是又没有解锁最后会造成死锁*/
 
           pthread_mutex_lock(&lock);
 
     while(1)
     {
 
 
            printf("t2 = %d\n",g_data++);
            sleep(1);
 
            if( g_data == 10)
            {
                 /*解锁*/
                 pthread_mutex_unlock(&lock);
                 pthread_exit(NULL);
            }
     }
}
 
int main ()
{
   pthread_t t1;
   pthread_t t2;
 
   /*初始化互斥锁*/
   pthread_mutex_init(&lock,NULL);
 
 
   /*创建t1和t2线程*/
   pthread_create(&t1,NULL,func1,NULL);
   pthread_create(&t2,NULL,func2,NULL);
 
 
   /*等待线程退出*/
   pthread_join(t1,NULL);
   pthread_join(t2,NULL);
 
   /*销毁互斥锁*/
   pthread_mutex_destroy(&lock);
    return 0;
}

该程序运行结果:

t1 = 0

t2 = 1

t2 = 2

t2 = 3

t2 = 4

t2 = 5

t2 = 6

t2 = 7

t2 = 8

t2 = 9   //解释:当这个g_data=10的时候t2线程解锁   之后t1的打印值为10  t1线程获得锁

t1 = 10

t1 = 11

t1 = 12

t1 = 13

互斥锁操作的实现为:获得锁  保证执行玩任务  释放锁才能给别的线程获得锁。获得锁的线程才可以运行。

2.2条件变量

条件变量允许一个线程休眠(阻塞等待)直至获取到另一个线程的通知(收到信号)再去执行自己的操作。条件变量可以利用全局变量。 条件变量通常搭配互斥锁来使用, 是因为条件的检测是在互斥锁的保护下进行的, 也就是说条件本身是由互斥锁保护的, 线程在改变条件状态之前必须首先锁住互斥锁, 不然就可能引发线程不安全的问题, 故需先获取到互斥锁再去获取条件变量。

两个线程分别操作条件变量 当变量到3时,fun1释放 fun2获取
#include <stdio.h>
#include <pthread.h>

//int pthread_create(pthread_t *restrict tidp, const pthread_attr_t *restrict attr, void *(*start_rtn)(void *), void *restrict arg);
int g_data = 0;

pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;//初始化条件变量
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;//初始化条件变量

void *func1(void *arg)
{
	printf("t1:%ld thread is create\n",(unsigned long)pthread_self());
	printf("t1:param is %d\n",*((int *)arg));
	static int cnt = 0;
	
	while(1){
		
		pthread_cond_wait(&cond,&mutex);
		printf("t1 run================================\n");

		printf("t1: %d\n",g_data);	
		g_data = 0;
		sleep(1);
		if(cnt++ == 10){
			exit(1);
		}
	}

}

void *func2(void *arg)
{
	printf("t2:%ld thread is create\n",(unsigned long)pthread_self());
	printf("t2:param is %d\n",*((int *)arg));
	
	
	while(1){

		printf("t2: %d\n",g_data);
		pthread_mutex_lock(&mutex);
		g_data++;
		if(g_data == 3){
			pthread_cond_signal(&cond);//条件变量为3时,发信号
		}
		pthread_mutex_unlock(&mutex);	//释放互斥锁
		sleep(1);
	}
}

int main()
{
	int ret;
	int param = 100;
	pthread_t t1;
	pthread_t t2;

//	pthread_mutex_init(&mutex,NULL);
//	pthread_cond_init(&cond,NULL);


	ret = pthread_create(&t1, NULL, func1,(void *)&param);
	if(ret == 0){
//		printf("main:create t1 success\n");
	}

	ret = pthread_create(&t2, NULL, func2,(void *)&param);
	if(ret == 0){
//		printf("main:create t2 success\n");
	}

//	printf("main:%ld\n",(unsigned long)pthread_self());

	pthread_join(t1,NULL);
	pthread_join(t2,NULL);

	pthread_mutex_destroy(&mutex);//释放
	pthread_cond_destroy(&cond);//释放
	return 0;
}

程序运行结果:

2.3自旋锁

        自旋”可以理解为“自我旋转”,这里的“旋转”指“循环”,比如 while 循环或者 for 循环。“自旋”就是自己在这里不停地循环,直到目标达成。而不像普通的锁那样,如果获取不到锁就进入阻塞。

        自旋锁并不会释放CPU的时间片,而是通过自旋的方式不断地去尝试获取锁,如果尝试获取失败,那么就一直尝试,直到成功获取到为止。
————————————————
关于自旋锁可看原文链接:https://blog.csdn.net/Paranoia_ZK/article/details/111664243

#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <unistd.h>
#include <string.h>
static pthread_spinlock_t spin;//定义自旋锁
static int g_count = 0;
static void *new_thread_start(void *arg)
{   
    int loops = *((int *)arg);
    int l_count, j; 
    for (j = 0; j < loops; j++)
    {
    pthread_spin_lock(&spin); //自旋锁上锁
    l_count = g_count;
    l_count++;
    g_count = l_count;
    pthread_spin_unlock(&spin);//自旋锁解锁
    }
    return (void *)0;
}

static int loops;
int main(int argc, char *argv[])
{
    pthread_t tid1, tid2;
    int ret;
/* 获取用户传递的参数 */
    if (2 > argc)
    loops = 100; //没有传递参数默认为 100次
    else
    loops = atoi(argv[1]);
/* 初始化自旋锁(私有) */
    pthread_spin_init(&spin, PTHREAD_PROCESS_PRIVATE);
/* 创建 2 个新线程 ,对g_count */
    ret = pthread_create(&tid1, NULL, new_thread_start, &loops);//loop被传入线程中 
    if (ret) {
    fprintf(stderr, "pthread_create error: %s\n", strerror(ret));
    exit(-1);
    }
    ret = pthread_create(&tid2, NULL, new_thread_start, &loops);
    if (ret) {
    fprintf(stderr, "pthread_create error: %s\n", strerror(ret));
    exit(-1);
    }
/* 等待线程结束 */
    ret = pthread_join(tid1, NULL);
    if (ret) {
    fprintf(stderr, "pthread_join error: %s\n", strerror(ret));
    exit(-1);
    }
    ret = pthread_join(tid2, NULL);
if (ret) {
    fprintf(stderr, "pthread_join error: %s\n", strerror(ret));
    exit(-1);
}
    printf("g_count = %d\n", g_count);
/* 销毁自旋锁 */
    pthread_spin_destroy(&spin);
    exit(0);
}

程序运行结果:

 2.4、线程中除了以上的同步机制,还有


(3)读写锁
(4)信号量
(5)屏障

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

陈俊帆Linux_Android

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值