【多线程】零碎记录

把自己之前几篇学习多线程知识的文章合成一篇,目的是方便离线保存。

(一)从demo开始

主要参考了下面这个视频内容(https://www.youtube.com/watch?v=fcHngVr4y7M)需FQ。

代码如下:

#include <iostream>
#include <unistd.h>
#include <pthread.h>

using namespace std;

int sum = 0;
void *add(void *);
pthread_mutex_t mut;

int main()
{
    pthread_t  thread[10];
    int num;
    long count;

    cout << "Enter the number of thread bewteen (1-10): ";
    cin >> num;

    cout << "Enter number to count to: ";
    cin >> count;

    pthread_mutex_init(&mut, NULL);

    for ( int x=0; x <num; ++x )
        pthread_create(&thread[x], NULL, add, (void *)count);

    for ( int x=0; x <num; ++x )
        pthread_join(thread[x],NULL);

    cout << sum << endl;
    return 0;
}

void *add(void *count)
{
    long num;
    num = (long) count;
    pthread_mutex_lock(&mut);
    for ( long x=1; x<=num; ++x )
    {
        sum += x;
        cout << sum << ‘\t‘ << x << endl;
    }
    pthread_mutex_unlock(&mut);
}

代码的功能很简单:

a. 有个一全局变量num用于累加的,每个线程都可以访问这个num

b. 向每个线程传入参数count,意义是每个线程内部对num累加多少

刚开始学习,不用纠结细节,先熟悉全貌。我总结需要大概了解以下几块内容,理解到哪算哪,有不到位的后面再改:

1)<pthread.h>

  含义是“Linux系统下多线程遵循POSIX接口标准”(如果是windows的话,又有另一套接口标准了)

2)pthread_create(p1, p2, p3, p4) (参照:http://man7.org/linux/man-pages/man3/pthread_create.3.html

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

  这是创建一个线程的函数。p2先不去管它,先看p1,p3和p4。

  p1:指向标示线程id号变量的指针(如果线程创建成功,p1指向的元素中就会被赋值一个该线程的唯一标示值)

  p3:指向线程执行的函数指针

  p4:指向传给线程参数的指针

  如果返回0:

    a. 一个新线程就run起来了

    b. 从“pthread_t *thread”指向的变量中,我们可以获得该线程的id号

    c. 甚至有可能在pthread_create返回0之前,这个新线程就执行完毕了

3)pthread_join(p1, p2) (https://computing.llnl.gov/tutorials/pthreads/man/pthread_join.txt

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

  功能是wait for thread termination,在代码中的目的是让主进程等待线程执行完毕再退出

  p1:要wait的thread是谁(即线程创建时产生的唯一标示id)

  p2:暂时还没用到

到这里,其实多线程的最简单的demo就可以跑起来了。但是这里会有问题:如果若干个线程同时对全局变量num操作,就会产生资源竞争的问题。

这时候就需要一种机制来避免这样的问题,其中一种机制就成为互斥量 mutex

用法:

1)先初始化互斥量pthread_mutex_init

2)在线程内部需要加锁的代码段前pthread_mutex_lock加锁

3)在资源使用结束后pthread_mutex_unlock解锁

关于mutex是啥,下面这段话解释的很好,直接粘过来了:

  • A mutex variable acts like a "lock" protecting access to a shared data resource. The basic concept of a mutex as used in Pthreads is that only one thread can lock (or own) a mutex variable at any given time. Thus, even if several threads try to lock a mutex only one thread will be successful. No other thread can own that mutex until the owning thread unlocks that mutex. Threads must "take turns" accessing protected data.

放到这个demo中来说,mut是一个互斥量,每个线程都可以访问,但是同时只能有一个线程对其成功lock;且一旦lock上了,其他线程就不能再lock或unlock了,只能由这个线程自身unlock。

这样,保证同时只有一个线程在操作num的值,因此这个demo中就线程同步了。

同步后的输出结果:

未用mutex同步时输入的结果:

对比以上的结果:没有加入mutex每次输出的结果可能是不同的;加了mutex的代码,每次输出的结果是稳定的。

(二)数据线程不安全的例子

找了一个比较完备的教程:https://computing.llnl.gov/tutorials/pthreads/

给线程传入参数,要保证数据是线程安全的,即传入线程的参数除了能让这个线程操作之外,外部的线程不会修改。

有下面一个例子:

/**
 * @file 1.thread.cpp
 * @brief
 * @author xbf   [email protected]
 * @version 1.0.0
 * @date 2015-08-04
 */

#include <pthread.h>
#include <iostream>
#include <unistd.h>

#define NUM_THREADS 5

using namespace std;

pthread_mutex_t mut;

void *print(void *threadid)
{
    pthread_mutex_lock(&mut);
    sleep(1);
    long tid;
    tid = *(long *)threadid;
    cout << "Thread " << tid << endl;
    pthread_mutex_unlock(&mut);
    pthread_exit(NULL);
}

int main()
{
    pthread_t threads[NUM_THREADS];
    pthread_mutex_init(&mut,NULL);
    for ( long t=0; t<NUM_THREADS; ++t )
    {
        cout << "main creating thread " << t << endl;
        int ret = pthread_create(&threads[t],NULL,print,(void *)&t);
        if ( ret!=0 )
        {
            cout << "error code " << ret << endl;
        }
    }
    pthread_exit(NULL);
}

这次给每个thread传入的是main for loop的计数变量t的引用。由于在main中每轮迭代t,所以等每个线程启动的时候访问的t就不是当时传入的t了。

这种情况就是传入线程的数据不安全。

时间: 2024-11-06 07:40:49

【多线程】零碎记录的相关文章

Java多线程——异常记录

Java多线程——异常记录 摘要:本文主要介绍了Java多线程中遇到的奇怪的异常. 部分内容来自以下博客: https://blog.csdn.net/historyasamirror/article/details/6709693 java.lang.IllegalMonitorStateException 在测试多线程通信的代码时,出现了这个异常. 代码如下: 1 public class Demo { 2 public static void main(String[] args) { 3

关于php多线程的记录

最近需要对3W台服务器进行下发脚本,如果一个一个执行,时间大约在2个小时,特别的慢,于是修改程序,采用php的多线程去分发,大概在10分钟左右完成,下面记录下这次的经验和理解: 我所理解的php的多线程实现的方式有两种,下面是官方的介绍: 1.官方的介绍:(转载自张宴的博客) 到php5.3以上的版本,php才算是真正的支持多线程,使用的是pthreads的扩展,php在处理多个循环的任务的时候,能够大大的缩短程序的执行时间. 大多数网站的性能瓶颈,不在php的服务器上,而是在mysql服务器上

python多线程学习记录

1.多线程的创建 import threading t = t.theading.Thread(target, args--) t.SetDeamon(True)//设置为守护进程 t.start(),启动线程 t.join(),阻塞当前线程,即使得在当前线程结束时,不会退出.会等到子线程结束之后才退出. 如果不加join语句,主线程不会等到子线程结束才结束,但却不会立即杀死该线程. 但是如果添加了SetDaemon(True),如果不加join,则会在主线程结束后马上杀死子线程. 如果join

在centos6.4上配置vim的一些零碎记录

上一篇日志已经step by step地实录了如何在本机mac上配置vim开发环境已经各种插件. 有了一定经验之后,把配置vim的环境到了实验室远程server上centos6.4的环境下配置,这台机器是内网服务器连外网比较麻烦. 主要就是多了server无法联网的条件,这个将来在公司配置开发机环境也是基本不能联网的,所以就当提前适应了吧. 这里把遇到的一些关键点记录下来,以便后个人后续查阅. 编译vim74 由于YouCompleteMe插件需要vim7.3高版本支持:而server上的vim

【多线程学习记录一(1)】创建java多线程

1)java多线程的创建方式有三种: 1.继承Thread类 2.实现Runnable接口 3.实现Callable接口 第一种: 1 //继承Thread类 2 class ExtendsThread extends Thread{ 3 public void run(){ 4 //do your stuff 5 } 6 } 7 ExtendsThread e = new ExtendsThread(); 8 e.start(); 第二种: 1 //实现Runnable接口 2 class I

sklearn源码解析:ensemble模型 零碎记录;如何看sklearn代码,以tree的feature_importance为例

最近看sklearn的源码比较多,好记性不如烂笔头啊,还是记一下吧. 整体: )实现的代码非常好,模块化.多继承等写的很清楚. )predict功能通常在该模型的直接类中实现,fit通常在继承的类中实现,方便不同的子类共同引用. 随机森林 和 GBDT )RandomForest的bootstrap是又放回的:GBDT则是无放回的. )实现的代码非常好,比如GBDT提供了一些小白不常用的函数[staged_decision_function,staged_predict]之类,对于调试观察每个D

多线程零碎整理

同步(synchronous)就是协同步调,按预定的先后次序进行运行.如:你说完,我再说."同"字从字面上容易理解为一起动作,其实不然,"同"字应是指协同.协助.互相配合.能表示前者意义的是"并发".那么异步就与同步相反,就像两个人走路,每个人按照自己的节奏走,步伐不一定要一致. 百科词条:CPU时间片轮转调度, 时间片轮转调度算法 同步,异步,并发,并行:b站,多线程第二个视频.1.2 并发和并行的区别就是一个人同时吃三个馒头和三个人同时吃三个

【多线程学习记录一(2)】继承Thread类和实现Runnable接口、Callable接口的区别

1)Runnable和Callable同是接口 * Callable的任务执行后可返回值,而Runnable的任务是不能返回值(是void);call方法可以抛出异常,run方法不可以 * 运行Callable任务可以拿到一个Future对象,表示异步计算的结果.它提供了检查计算是否完成的方法,以等待计算的完成,并检索计算的结果.通过Future对象可以了解任务执行情况,可取消任务的执行,还可获取执行结果. * 加入线程池运行,Runnable使用ExecutorService的execute方

GCD 多线程 ---的记录 iOS

先写一个GCD static UserInfoVoModel *userInfoShare = nil; +(instancetype)shareUserInfoVoModel { static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ userInfoShare = [[UserInfoVoModel alloc] init]; }); return userInfoShare; }