Linux多线程(补充锁及某些问题)
ฅ'ω'ฅ♪

Linux多线程(补充锁及某些问题)

锁?

给线程加锁可以解决多个线程操作同一个共享变量时,就可能会出现可见性,原子性和有序性的问题。

可见性问题

将一个线程对共享变量对另一个线程可见称之为可见性,

由于在多核计算机中,线程获取CPU的执行权,

操作共享变量之后可能会将操作后的数据存入CPU缓存(也就是线程私有栈)

如果线程A和线程B都对变量为进行操作,

然后将操作后的数据存入各自的私有栈中,就会出现可见性问题。

原子性问题

原子性:一个操作的内部状态对外界不可见称之为原子性,且一般认为一条cpu指令是具有原子性的,而一条高级语句可能会分多条指令执行。

例如简单的:i=i+ 1

  1. 将i的值从内存读取到cpu寄存器中。
  2. 执行i+1操作得到a值
  3. 将a值赋值给i并写入内存中(或是cpu缓存中,视情况)

在每个cpu指令执行完之后都有可能发生线程的切换

原因是在操作系统允许某个线程的一小段时间之后就会发生任务切换,这一小段时间就是大家熟知的“时间片”。

而早期的操作系统是基于进程之间调用cpu的,不同的进程之间是不共享内存空间的。所以进程要做任务切换就需要切换物理内存地址,

而一个进程创建的所有线程都是共享一个内存空间的。

所以,在线程池中线程切换的成本比较低,现在的操作系统都是基于更轻量化的线程来调度。

类比其他field中并行操作的弊端。(如关系型数据库中的并行操作)

有序性

一条cpu指令简单地可以分为以下几步:

  1. 取值IF
  2. 译码和取寄存器操作数ID
  3. 执行或者有效地址计算EX
  4. 存储器访问MEM
  5. 写回WB

目前可以实现并发程序的方法有Apache模型(Process Per Connection,简称PPC),TPCThread PerConnection)模型,以及select模型和poll模型、Epoll模型。

  1. Apache模型,在并发上是通过多进程实现的
  2. PC模型,是通过多线程实现的,但是这种方式在大量进程/线程切换时会造成大量的开销。
  3. select模型,是通过一种轮询机制来实现的
  4. poll模型,与select类似,也是通过轮询来实现,但它与select模型的区别在于Socket数量没有限制
  5. Epoll模型,在poll模型的基础之上不使用轮询,而使用基于内核提供的反射模式。

多线程

编写Linux下的多线程程序,需要使用头文件pthread.h,连接时需要使用库libpthread.a

线程与进程相比,是一种非常节俭的多任务操作方式。

在Linux系统下,启动一个新的进程必须分配独立的地址空间,并且建立众多的数据表来维护代码段、堆栈段和数据段。同时要进行数据的传递只能通过进程间通信的方式进行。

相比之下,同一进程下的线程共享数据空间,所以一个线程的数据可以直接被其他线程所用。

多线程优点

  1. 对于一个进程中的多个线程,因为其间使用相同的地址空间,而且线程之间彼此切换所需的时间也远远小于进程之间切换所需要的时间。
  2. 一个进程的平均开销大约是一个线程的30倍左右。
  3. 使得多cpu系统更有效,操作系统会保证当线程数大于cpu数目时,不同的线程运行不同的cpu上。
  4. 改善程序结构。将一个又长又复杂的进程分为多个线程,使其成为几个独立或半独立的运行部分,会有利于程序的理解和修改。

创建线程

#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的参数

pthread的库不是Linux系统的库,

在进行编译的时候要加上-lpthread,

gcc filename -lpthread

终止线程

  1. 线程从启动例程中返回
  2. 线程可以被另一个进程终止
  3. 线程自身调用pthread_exit()
#include <pthread.h>
void pthread_exit(void *rval_ptr)
//
//功能:终止调用线程
//ravl_ptr:线程退出返回值的指针

等待线程

#include <pthread.h>
int pthread_join(pthread_t tid, void ** rval_ptr)
功能:阻塞调用线程,直到指定的线程终止
tid:等待退出的线程id
rval_ptr:线程退出的返回值的指针

线程标识

#include <stdio.h>
#include <pthread.h>
#include <unistd.h> /*getpid()*/

void *create(void *arg)
{
    printf("New thread .... \n");
    printf("This thread's id is %u  \n", (unsigned int)pthread_self());
    printf("The process pid is %d  \n",getpid());
    return (void *)0;
} 

int main(int argc,char *argv[])
{
    pthread_t tid;
    int error;

    printf("Main thread is starting ... \n");

    error = pthread_create(&amp;tid, NULL, create, NULL);

    if(error)
    {
        printf("thread is not created ... \n");
        return -1;
    }
    printf("The main process's pid is %d  \n",getpid());
    sleep(1);
    return 0;
}

线程主动调用pthread_exit或者从线程函数中return都将使线程正常退出,这是可预见的退出方式;

非正常终止是线程在其他线程的干预下,或者由于自身运行出错而退出,这种退出方式是不可预见的。

从pthread_cleanup_push的调用点到pthread_cleanup_pop之间的程序段中终止动作(包括调用pthread_exit()和异常终止,不包括return

都将执行pthread_cleanup_push()所指定的清理函数。

CANCEL

-评论-

Here you can post what you want to say, if you have more information please contact me by the following way.

-昵称-
-QQ-
-邮箱-
想说些什么?
-SUBMIT-

-电联 Phone-

+86 18520664652

-邮箱 Email-

boogieLing_o@163.com

boogieLing_o@qq.com

Your name. OS platform Browser model

What do you want to say?

created time

游說萬乘苦不早,著鞭跨馬涉遠道。

阿凌的貓爬架

幸會,

激活Ubuntu

转到“设置”以激活Ubuntu。

R0's board.