2022/3/7

线程:

线程的优点: 和进程相比,它是一种非常“节俭”的多任务操作方式.在Linux系统下,启动一个新的进程必须分配给它独立的地址空间,建立众多的数据表来维护它的代码段、堆栈段和数据段,这是一种"昂贵"的多任务工作方式。运行于一个进程中的多个线程,它们之间使用相同的地址空间,而且线程间彼此切换所需的时间也远远小于进程间切换所需要的时间.据统计,一个进程的开销大约是一个线程开销的30倍左右

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

除了以上所说的优点外,多线程程序作为一种多任务、并发的工作方式,有如下优点: 使多CPU系统更加有效.操作系统会保证当线程数不大于CPU数目时,不同的线程运行于不同的CPU上. 改善程序结构.一个既长又复杂的进程可以考虑分为多个线程,成为几个独立或半独立的运行部分,这样的程序会利于理解和修改.

注:Linux系统下的多线程遵循POSIX线程接口,称为pthread。编写Linux下的多线程程序,需要使用头文件pthread.h,连接时需要使用libpthread.a

#include <pthread.h>
int pthread_create(pthread_t * tidp,const pthread_attr_t*attr,void*(*start_rtn)(void),void*arg)

tidp:线程id
attr: 线程属性(通常为空)
start_rtn:线程要执行的函数
arg:start_rtn的参数

 编译:编译时需要加上 -lpthread;

终止线程:如果进程中任何一个线程中调用exit或_exit,那么整个进程都会终止。线程的正常退出方式有: (1) 线程从启动例程中返回 (2) 线程可以被另一个进程终止 (3) 线程自己调用pthread_exit函数

线程退出
#include <pthread.h>
   void pthread_exit(void * rval_ptr)

功能:终止调用线程
Rval_ptr:线程退出返回值的指
线程等待
#include <pthread.h>

     int pthread_join(pthread_t tid,void **rval_ptr)

功能:阻塞调用线程,直到指定的线程终止。

Tid :等待退出的线程id

Rval_ptr:线程退出的返回值的指针

 代码示例:


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

char message[] = "hello world";

void * tid_work(void * arg)
{
	printf("thread function in running argument is %s \n", (char *)arg);

    sleep(3);

	strcpy(message, "Bye");

	pthread_exit("thank you for your CPU time");	

}

int main()
{
    pthread_t tid;
	int ret;
	void * thread_val;

    ret = pthread_create(&tid, NULL, tid_work, (void *)message);

    if (ret != 0)
	{
		perror("create thread error");
		exit(-1);
	}

    printf("waiting for thread to finish...\n");

	ret = pthread_join(tid, &thread_val);

	if (ret != 0)
	{
		perror("thread join error");
		exit(-1);
	}

	printf("thread joined, it returned %s\n", (char *)thread_val);

	printf("message is now: %s\n", message);

	return 0;
}

线程同步 :进行多线程编程,因为无法知道哪个线程会在哪个时候对共享资源进行操作,因此让如何保护共享资源变得复杂,通过下面这些技术的使用,可以解决 线程之间对资源的竞争:                 1 互斥量Mutex                 2 信号灯Semaphore                 3 条件变量Conditions

 

互斥量:

为什么需要使用互斥量?

Item * p =queue_list;
Queue_list=queue_list->next;
process_job(p);
free(p);
     当线程1处理完Item *p=queue_list后,系统停止线程1的运行,改而运行线程2。线程2照样取出头节点,然后进行处理,最后释放了该节点。过了段时间,线程1重新得到运行。而这个时候,p所指向的节点已经被线程2释放掉,而线程1对此毫无知晓。他会接着运行process_job(p)。而这将导致无法预料的后果!

对于这种情况,系统给我们提供了互斥 量.线程在取出头节点前必须要等待互斥量,如果此时有其他线程已经获得该互斥量,那么该线程将会阻塞在这里.只有等到其他线程释放掉该互斥量后,该线程才有可能得到该互斥量。互斥量从本质上说就是一把锁, 提供对共享资源的保护访问

创建:

在Linux中, 互斥量使用类型pthread_mutex_t表示.在使用前, 要对它进行初始化:        

对于静态分配的互斥量, 可以把它设置为默认的mutex对象PTHREAD_MUTEX_INITIALIZER        对于动态分配的互斥量, 在申请内存(malloc)之后, 通过pthread_mutex_init进行初始化, 并且在释放内存(free)前需要调用pthread_mutex_destroy

#include <pthread.h>
 int pthread_mutex_init(pthread_mutex_t 、*mutex,const pthread_mutexattr_t *attr)
 int pthread_mutex_destroy(pthread_mutex_t *mutex)
在操作完成后,必须给互斥量解锁,也就是前面所说的释放。这样其他等待该锁的线程才有机会获得该锁,否则其他线程将会永远阻塞。
int pthread_mutex_unlock(pthread_mutex_t *mutex)

注意:在操作完成后要解锁!并非知识释放!

 int pthread_mutex_unlock(pthread_mutex_t *mutex)

互斥量PK信号量:

Mutex是一把钥匙,一个人拿了就可进入一个房间,出来的时候把钥匙交给队列的第一个。    Semaphore是一件可以容纳N人的房间,如果人不    满就可以进去,如果人满了,就要等待有人出来。    对于N=1的情况,称为binary semaphore。 Binary semaphore与Mutex的差异: 1. mutex要由获得锁的线程来释放(谁获得,谁释放)。而semaphore可以由其它线程释放 2. 初始状态可能不一样:mutex的初始值是1 ,semaphore的初始值可能是0(或者为1)

 

条件变量:

创建条件变量
      pthread_cond_t  cond; 
2、条件变量初始化
     a、静态初始化
      PTHREAD_COND_INITIALIZER
     b、动态初始化
      int pthread_cond_init(
                      pthread_cond_t * cond,
                      pthread_condattr_t * cond_attr);
3·条件变量撤销
     int pthread_cond_destroy(
                                     pthread_cond_t *cond);
4、条件变量等待
    int pthread_cond_wait(
                        pthread_cond_t * cond,
                        pthread_mutex_t *mutex);
      
             unlock -> wait->lock
int pthread_cond_timedwait(
                       pthread_cond_t *cond;
                       pthread_mutex_t *mutex;
                       const struct timespec *sbstime);
         ETIMEOUT
      typedef struct timespec
      {
              time_t  tv_sec;
              long  tv_nsec;
        } timespec_t;

线程1
 pthread_mutex_lock(&mutex);
 if(条件不成立)
 pthread_cond_wait(&cond,*mutex);
  修改条件
 pthread_mutex_unlock(&mutex);
线程2 
    pthread_mutex_lock(&mutex);
    使条件满足
    pthread_cond_signal(&cond);

    pthread_mutex_unlock(&mutex);

int pthread_cond_signal(
                                pthread_cond_t *cond);
 int pthread_cond_broadcast(
                                pthread_cond_t *cond);

 如下代码实现消费者和生产者问题:

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

#define BUFFER_SIZE 16
#define OVER -1

struct prod
{
    int buffer[BUFFER_SIZE];
    pthread_mutex_t lock;
    pthread_cond_t notempty;
    pthread_cond_t notfull;

    int readpos,writepos;
};

struct prod buf;

void init(struct prod *b)
{
    pthread_mutex_init(&b->lock,NULL);
    pthread_cond_init(&b->notempty,NULL);
    pthread_cond_init(&b->notfull,NULL);

    b->readpos = b->writepos =0;
}

void put(struct prod * b,int data)
{
    pthread_mutex_lock(&b->lock);
    if ((b->writepos+1)%BUFFER_SIZE == b->readpos)//满
    {
        pthread_cond_wait(&b->notfull,&b->lock);
    }
    b->buffer[b->writepos] = data;
    b->writepos++;
    if (b->writepos >= BUFFER_SIZE)
    {
        b->writepos =0;
    }
    
    pthread_cond_signal(&b->notempty);

    pthread_mutex_unlock(&b->lock);
}
void * producer(void)
{
    int n;
    for ( n = 0; n < 20; n++)
    {
        printf("%d---->",n+1);
        put(&buf,n+1);

    }
    put(&buf,OVER);

    return NULL;

}
int get(struct prod *b)
{
    int data;
    pthread_mutex_lock(&b->lock);

    if (b->writepos == b->readpos)      //为空
    {
        pthread_cond_wait(&b->notempty,&b->lock);
        
    }
    
    data = b->buffer[b->readpos];
    b->readpos = (b->readpos +1)%BUFFER_SIZE;
    pthread_cond_signal(&b->notfull);

    pthread_mutex_unlock(&b->lock);

    return data;
}
void * customer(void)
{
    int d;
    while (1)
    {
        d=get(&buf);
        if (OVER == d)
        {
            break;
        }
        printf("%d---->\n",d);
    }
    return NULL;
    
}

int main()
{
    pthread_t th_p,th_c;

    init(&buf);

    pthread_create(&th_p,NULL,(void *)producer,NULL);

    pthread_create(&th_c,NULL,(void *)customer,NULL);
    
    pthread_join(th_p,NULL);

    pthread_join(th_c,NULL);


    return 0;
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值