linux 多线程

使用线程的理由之一是:和进程相比,它是一种“节俭”的多任务操作方式。在linux系统下,启动一个新的进程必须分配给他独立的地址空间,建立众多的数据表来维护它的代码段、堆栈段和数据段,这是一种“昂贵的”多任务工作方式。

运行于一个进程中的多个线程,他们之间使用相同的地址空间,而且线程间彼此切换所用的时间也远远小于进程间切换所用的时间。据统计,一个进程的开销大约是一个线程开销的30倍左右。

使用多线程理由之二:

线程间方便的通信机制。对不同进程来说,他们具有独立的数据空间,要进行数据传递只能通过进程间通信的方式进行,这种方式不仅耗时而且很不方便。线程则不然,由于同一进程下的线程之间共享数据空间,所以一个线程的数据可以直接为其它线程所用,这不仅快捷,而且方便。

除了以上优点之外,多线程作为一种多任务、并发的工作方式,有如下优点:

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

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

 

获取线程号方法

  syscall(SYS_gettid)

  • 设置线程名

#include <sys/prctl.h>
 
//名字的长度最大为15字节,且应该以'\0'结尾
#define set_thread_name(name)   prctl(PR_SET_NAME, name, 0, 0, 0);
  • 获取线程名
//char tname[16];
#define get_thread_name(name)   prctl(PR_GET_NAME, name)

 

#include <unistd.h>
#include <stdio.h>
#include <pthread.h>
 #include <sys/prctl.h>
#include <sys/syscall.h>
/*
* 线程的执行函数
* */
void *thread(void *str)
{
    int *num;
	num=(int *)str;
	  prctl(PR_SET_NAME,"THREAD1");
	printf("create parameter is %d\n",*num);
	printf("process id: %d\tthread id: %lu\n", getpid(),pthread_self());
	//printf("process id: %d\tthread tid: %lu\n", getpid(),pthread_self()->tid);
	printf("child thread lwpid = %u\n", syscall(SYS_gettid));
	sleep(30);
	return (void*)0;
	
}


/*
* 程序入口
* */
int main()
{
    pthread_t pth;
    int error;
	int test=4;
	int *attr=&test;

	/*创建线程并执行线程执行函数*/
    error = pthread_create(&pth, NULL, thread, (void *)attr);  
	if(error)
	{
	printf("pthread_create is created is not create...\n");
	return -1;
	}
    sleep(1);

     pthread_join(pth, NULL);
    printf("pthread_create is created\n");
    
    return 0;
}

 

https://www.cnblogs.com/missmzt/p/4581919.html

线程创建

  函数原型:int pthread_create(pthread_t *tidp, const pthread_attr_t *restrict attr,  void *(*start_rtn)(void),   void *restrict arg);

  返回值:若是成功建立线程返回0,否则返回错误的编号。  

   形式参数:

pthread_t *tidp 要创建的线程的线程id指针,即,创建成功后,该指针指向的内存存放创建线程的id;

const pthread_attr_t *restrict attr创建线程时的线程属性;

void* (start_rtn)(void)返回值是void类型的指针函数;

void *restrict arg start_rtn的形参。

线程挂起:该函数的作用使得当前线程挂起,等待另一个线程返回才继续执行。也就是说当程序运行到这个地方时,程序会先停止,然后等线程id为thread的这个线程返回,然后程序才会断续执行。

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

  参数说明如下:thread等待退出线程的线程号;value_ptr退出线程的返回值。

线程退出

  函数原型:void pthread_exit(void *rval_ptr);

获取当前线程id

  函数原型:pthread_t pthread_self(void);

       syscall(SYS_gettid)

互斥锁

创建pthread_mutex_init;

销毁pthread_mutex_destroy;

加锁pthread_mutex_lock;

解锁pthread_mutex_unlock。

条件锁 

创建pthread_cond_init

销毁pthread_cond_destroy;

触发pthread_cond_signal;

广播pthread_cond_broadcast S;

等待pthread_cond_wait

 

 

互斥锁与条件变量以及信号量介绍:
互斥锁:互斥锁用来对共享资源的互斥访问,一个时刻只允许一个线程资源的修改.
pthread_mutex_t mutex; 
  
pthread_mutex_lock(&mutex);
pthread_mutex_unlock(&mutex);
条件变量: 条件变量的作用是当一个线程的继续运行依赖于一个条件,而这个条件是由另一个线程触发的,这时候使用互斥锁是不行的.
pthread_cond_t cond;  

pthread_cond_wait(&cond,&mutex);  
pthread_cond_signal(&cond);
pthread_cond_wait,两个参数第一个是等待的条件量,第二个是要释放的互斥锁,
pthread_cond_wait时,阻塞当前线程,等待条件变化,同时释放自己占有的互斥锁,使得其他线程可以运行从而触发条件量,
在另一个线程中使用pthread_cond_signal 来告诉被阻塞的线程继续运行.
信号量:当共享资源有限时,如消费缓冲区,多个线程同时去进行消费,当缓冲区资源为0时,不允许新的线程进入,则使用信号量机制进行限制.
信号量一般和互斥锁接合使用,前者用来限制线程进入缓冲区的数目,后者用于互斥的修改缓冲区资源.
sem_t sem_id;   
sem_wait(&sem_id);取得信号量,sem_id的值--,若为0,则等待  
sem_post(&sem_id);释放信号量,sem_id++

 

 

条件变量配合  互斥锁(还有读写锁和自旋锁)

https://blog.csdn.net/qq_41071068/article/details/104641225

 

#include<iostream>
#include<cstdio>
#include<cstring>
#include<unistd.h>
#include<pthread.h>
using namespace std;
 
int cate = 0;
pthread_mutex_t mutex;
pthread_cond_t foodie_cond;
pthread_cond_t chief_cond;
void* foodie(void* arg){//吃货线程
    int n = *(int*)arg;
    while(1){
        pthread_mutex_lock(&mutex);
        while(cate == 0){//没有美食只能等等着厨师做好之后叫我了
            pthread_cond_wait(&foodie_cond, &mutex);
        }
        --cate;
        cout << "吃货" << n <<":有好吃的, 马上吃一碗\n";
        pthread_mutex_unlock(&mutex);
        pthread_cond_signal(&chief_cond);
    }
    return NULL;
}
void* chief(void* arg){//厨师线程
    int n = *(int*)arg;
    while(1){
        pthread_mutex_lock(&mutex);
        while(cate == 1){
            pthread_cond_wait(&chief_cond, &mutex);
        }
        ++cate;//做一份美食, 唤醒一下吃货, 别睡了, 起来吃好吃的啦
        cout << "大厨" << n <<":本大厨做了一份美食\n";
        pthread_mutex_unlock(&mutex);
        pthread_cond_signal(&foodie_cond);
    }
}
int main(){
    pthread_t foodie_tid[5], chief_tid[5];
    int n[5] = {1, 2, 3, 4, 5};
    int ret;
    pthread_mutex_init(&mutex, NULL);
    pthread_cond_init(&foodie_cond, NULL);
    pthread_cond_init(&chief_cond, NULL);
    for(int i = 0; i < 5; ++i){
        ret = pthread_create(&foodie_tid[i], NULL, foodie, (void*)(n + i));
        if(ret){
            fprintf(stderr, "foodie_thread%d create:%s\n", i + 1, strerror(ret));
            return -1;
        }
    
    }
    for(int i = 0; i < 5; ++i){
        ret = pthread_create(&chief_tid[i], NULL, chief, (void*)(n + i));
        if(ret){
            fprintf(stderr, "chief_thread%d create:%s\n", i + 1, strerror(ret));
            return -1;
        }
    }
    for(int i = 0; i < 5; pthread_join(foodie_tid[i], NULL), ++i);
    for(int i = 0; i < 5; pthread_join(chief_tid[i], NULL), ++i);
    pthread_mutex_destroy(&mutex);
    pthread_cond_destroy(&foodie_cond);
    pthread_cond_destroy(&chief_cond);
    return 0;
}

注:一个Condition Variable总是和一个Mutex搭配使用的。一个线程可以调用
pthread_cond_wait在一一个Condition Variable上阻塞等待,这个函数做以下三步操作:
1. 释放Mutex
2. 阻塞等待
3. 当被唤醒时,重新获得Mutex并返回

 

为什么pthread_cond_wait()中要传入互斥锁?
某个执行流在判断条件变量的条件是否满足之前, 要先给条件变量加锁, 如果不满足条件, 则这个执行流阻塞进入等待队列, 但此时这个执行流并没有释放条件变量的锁, 在这个执行流等待过程中, 没有其他的执行流能访问修改条件变量的判断条件(因为加的锁没解锁). 这就导致了其他执行流因为获取不到锁资源而陷入等待(没人修改条件判断), 而这个在条件变量的等待队列执行中等待的执行流因为没有其他执行流唤醒而一直在等待, 这就造成了死锁.

所以说, 在进入条件变量的等待队列之前, 需要先给自己所拥有的锁解锁, 再进入等待, 这样其他的执行流才能拿到条件变量的判断条件的锁资源, 然后修改判断条件, 从而唤醒这个等待的执行流 
 

 

互斥锁体现的是一种竞争, 我离开了, 通知你进来.   

条件变量体现的是一种协作, 我准备好了, 通知你开始吧.

简单来说, 是为了效率, 即为了避免有线程不断轮循检查条件是否满足而降低效率, 具体来看 :

两个线程操作同一临界区时, 通过互斥锁保护, 若A线程已经加锁, B线程再加锁时候会被阻塞, 直到A释放锁, B再获得锁运行, 进程B必须不停的主动获得锁, 检查条件, 释放锁, 再获得锁, 再检查, 再释放.  一直到满足运行的条件的时候才可以 (而此过程中其他线程一直在等待该线程的结束), 这种方式是比较消耗系统的资源的. 而条件变量同样是阻塞, 但需要通知才能唤醒, 线程被唤醒后, 它将重新检查判断条件是否满足, 如果还不满足, 该线程就又阻塞在这里, 等待条件满足后被唤醒, 节省了线程不断检查条件浪费的资源. 这个过程一般用while语句实现.  当线程B发现被锁定的变量不满足条件时会自动的释放锁并把自身置于等待状态, 让出CPU的控制权给其它线程. 其它线程此时就有机会去进行操作, 当修改完成后再通知那些由于条件不满足而陷入等待状态的线程. 这是一种通知模型的同步方式, 大大的节省了CPU的计算资源, 减少了线程之间的竞争, 而且提高了线程之间的系统工作的效率. 
 

 

 
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值