标签归档:线程

Linux进程或线程绑定到CPU

为了让程序拥有更好的性能,有时候需要将进程或线程绑定到特定的CPU,这样可以减少调度的开销和保护关键进程或线程。

进程绑定到CPU

Linux提供一个接口,可以将进程绑定到特定的CPU:

#include

int sched_setaffinity(pid_t pid, size_t cpusetsize, const cpu_set_t *mask);

int sched_getaffinity(pid_t pid, size_t cpusetsize, cpu_set_t *mask);

参数

pid:进程的id号,如果pid为0,则表示本进程

cpusetsize:mask的大小

mask:运行进程的CPU,可以通过以下函数操作mask

#define CPU_SET(cpu, cpusetp) //设置cpu

#define CPU_CLR(cpu, cpusetp) //删除cpu

#define CPU_ISSET(cpu, cpusetp) //判断cpu

#define CPU_ZERO(cpusetp) //初始化为0

示例代码 

#include
#include
#include #include
 
void WasteTime()
{
    int abc = 10000000;
    while(abc–)
    {
        int tmp = 10000*10000;
    }
    sleep(1);

}

int main(int argc, char **argv)
{
    cpu_set_t mask;
    while(1)
    {
 
        CPU_ZERO(&mask);
        CPU_SET(0, &mask);
        if (sched_setaffinity(0, sizeof(mask), &mask) < 0) {
            perror(“sched_setaffinity”);
        }
        WasteTime();
 
        CPU_ZERO(&mask);
        CPU_SET(1, &mask);
        if (sched_setaffinity(0, sizeof(mask), &mask) < 0) {
            perror(“sched_setaffinity”);
        }
        WasteTime();
   
        CPU_ZERO(&mask);
        CPU_SET(2, &mask);
        if (sched_setaffinity(0, sizeof(mask), &mask) < 0) {
            perror(“sched_setaffinity”);
        }
        WasteTime();
   
        CPU_ZERO(&mask);
        CPU_SET(3, &mask);
        if (sched_setaffinity(0, sizeof(mask), &mask) < 0) {
            perror(“sched_setaffinity”);
        }
        WasteTime();
    }
}

 

 

测试

编译之后运行程序,输入命令top -p 进程id,输入f,输入j,输入回车,可以看到进程在cpu0123之间不停切换。

线程绑定到CPU

不仅仅进程可以绑定到CPU,线程也可以。Linux提供一个接口,可以将线程绑定到特定的CPU:

#include

int pthread_setaffinity_np(pthread_t thread, size_t cpusetsize, const cpu_set_t *cpuset);

int pthread_getaffinity_np(pthread_t thread, size_t cpusetsize, cpu_set_t *cpuset);

该接口与进程绑定到CPU的接口的使用方法基本一致。

当进程绑定到特定的CPU之后,线程还是可以绑定到其他的CPU的,没有冲突。

示例代码

 

#include
#include #include #include
#include

void WasteTime()
{
    int abc = 10000000;
    while(abc–)
    {
        int tmp = 10000*10000;
    }
    sleep(1);

}

void *thread_func(void *param)
{
    cpu_set_t mask;
    while(1)
    {
        CPU_ZERO(&mask);
        CPU_SET(1, &mask);

        if (pthread_setaffinity_np(pthread_self(), sizeof(mask),
            &mask) < 0) {
            perror(“pthread_setaffinity_np”);
        }
 
        WasteTime();

        CPU_ZERO(&mask);
        CPU_SET(2, &mask);
        if (pthread_setaffinity_np(pthread_self(), sizeof(mask),
            &mask) < 0) {
            perror(“pthread_setaffinity_np”);
        }

        WasteTime();
    }
}
 
void *thread_func1(void *param)
{
    cpu_set_t mask;
    while(1)
    {
        CPU_ZERO(&mask);
        CPU_SET(3, &mask);

        if (pthread_setaffinity_np(pthread_self(), sizeof(mask),
            &mask) < 0) {
            perror(“pthread_setaffinity_np”);
        }
 
        WasteTime();

        CPU_ZERO(&mask);
        CPU_SET(4, &mask);
        if (pthread_setaffinity_np(pthread_self(), sizeof(mask),
            &mask) < 0) {
            perror(“pthread_setaffinity_np”);
        }

        WasteTime();
    }
}
 
int main(int argc, char *argv[])
{
    cpu_set_t mask;
    CPU_ZERO(&mask);
    CPU_SET(0, &mask);
    if (sched_setaffinity(0, sizeof(mask), &mask) < 0) {
        perror(“sched_setaffinity”);
    }

    pthread_t my_thread;
 
    if (pthread_create(&my_thread, NULL, thread_func,
        NULL) != 0) {
        perror(“pthread_create”);
    }
    if (pthread_create(&my_thread, NULL, thread_func1,
        NULL) != 0) {
        perror(“pthread_create”);
    }
    while(1) { WasteTime(); }
    pthread_exit(NULL);

}
 

测试

编译运行之后,输入命令top -p 进程id,输入f,输入j,输入回车,输入H,可以看到主线程一直保持在cpu0,一个线程在cpu12之前切换,另一个线程在cpu34之间切换。

Linux下查看进程和线程

<

div id=”content” contentScore=”5444″>在Linux中查看线程数的三种方法

1、top -H
手册中说:-H : Threads toggle
加上这个选项启动top,top一行显示一个线程。否则,它一行显示一个进程。
2、ps xH
手册中说:H Show threads as if they were processes
这样可以查看所有存在的线程。
3、ps -mp
手册中说:m Show threads after processes
这样可以查看一个进程起的线程数。

查看进程

  1. top 命令

top命令查看系统的资源状况

  load average表示在过去的一段时间内有多少个进程企图独占CPU

  zombie 进程 :不是异常情况。一个进程从创建到结束在最后那一段时间遍是僵尸。留在内存中等待父进程取的东西便是僵尸。任何程序都有僵尸状态,它占用一点内存资源,仅仅是表象而已不必害怕。如果程序有问题有机会遇见,解决大批量僵尸简单有效的办法是重起。kill是无任何效果的stop模式:与sleep进程应区别,sleep会主动放弃cpu,而stop是被动放弃cpu ,例单步跟踪,stop(暂停)的进程是无法自己回到运行状态的。

  cpu states:

  nice:让出百分比irq:中断处理占用

  idle:空间占用百分比 iowait:输入输出等待(如果它很大说明外存有瓶颈,需要升级硬盘(SCSI))

  Mem:内存情况

  设计思想:把资源省下来不用便是浪费,如添加内存后free值会不变,buff值会增大。 判断物理内存够不够,看交换分区的使用状态。

  交互命令:

  [Space]立即刷新显示

  [h]显示帮助屏幕

  [k] 杀死某进程。你会被提示输入进程 ID 以及要发送给它的信号。 一般的终止进程可以使用15信号;如果不能正常结束那就使用信号9强制结束该进程。默认值是信号15。在安全模式中此命令被屏蔽。

  [n] 改变显示的进程数量。你会被提示输入数量。

  [u] 按用户排序。

  [M] 按内存用量排序。

  [o][O] 改变显示项目的顺序。

  [P] 根据CPU使用百分比大小进行排序。

  [T] 根据时间/累计时间进行排序。

  [Ctrl+L] 擦除并且重写屏幕。

  [q] 退出程序。

  [r] 重新安排一个进程的优先级别。系统提示用户输入需要改变的进程PID以及需要设置的进程优先级值。输入一个正值将使优先级降低,反之则可以使该进程拥有更高的优先权。默认值是10。

  [S] 切换到累计模式。

  [s] 改变两次刷新之间的延迟时间。系统将提示用户输入新的时间,单位为s。如果有小数,就换算成m s。输入0值则系统将不断刷新,默认值是5 s。需要注意的是如果设置太小的时间,很可能会引起不断刷新,从而根本来不及看清显示的情况,而且系统负载也会大大增加。

  缩写含义:

  PID每个进程的ID

  USER进程所有者的用户名

  PRI每个进程的优先级别

  NI每个优先级的值

  SIZE 进程的代码大小加上数据大小再加上堆栈空间大小的总数,单位是KB RSS 进程占用的物理内存的总数量,单位是KB

  SHARE进程使用共享内存的数量

  STAT 进程的状态。其中S代表休眠状态;D代表不可中断的休眠状态;R代表运行状态;Z代表僵死状态;T代表停止或跟踪状态

  %CPU进程自最近一次刷新以来所占用的CPU时间和总时间的百分比

  %MEM进程占用的物理内存占总内存的百分比

  TIME进程自启动以来所占用的总CPU时间

  CPU CPU标识

  COMMAND进程的命令名称

  1. ps命令

ps查看当前用户的活动进程,如果加上参数可以显示更多的信息,如-a,显示所有用户的进程

  ps ax :tty值为“?”是守护进程,叫deamon 无终端,大多系统服务是此进程,内核态进程是看不到的

      ps axf :看进程树,以树形方式现实进程列表敲 ,init是1号进程,系统所有进程都是它派生的,杀不掉

      ps axm :会把线程列出来。在linux下进程和线程是统一的,是轻量级进程的两种方式。

  ps axu :显示进程的详细状态。

  vsz:说此进程一共占用了多大物理内存。

  rss:请求常驻内存多少

查看线程

其实linux没有线程,都是用进程模仿的

  1. ps -ef f
    用树形显示进程和线程,比如说我想找到proftp现在有多少个进程/线程,可以用
    $ ps -ef f | grep proftpd
    nobody 23117 1 0 Dec23 ? S 0:00 proftpd:  (accepting  connections) 
    jack 23121 23117 0 Dec23 ? S 7:57 _ proftpd: jack – ftpsrv:  IDLE
    jack 28944 23117 0 Dec23 ? S 4:56 _ proftpd: jack – ftpsrv:  IDLE
    这样就可以看到proftpd这个进程下面挂了两个线程。
    在Linux下面好像因为没有真正的线程,是用进程模拟的,有一个是辅助线程,所以真正程序开的线程应该只有一个。

  2. pstree -c也可以达到相同的效果
    $ pstree -c | grep proftpd
    |-proftpd-+-proftpd
    | `-proftpd

  3. cat /proc/${pid}/status
    可以查看大致的情况

4.  pstack

有些系统可以用这个东东,可以查看所有线程的堆栈

如何查看进程中各线程的内存占用情况?

用ps aux只能查看到进程,如果进程里面使用了pthread编程,用什么命令才能查询到进程里的线程资源占用?
ps aux | grep不尼/div>

基于pthread的线程池,C++实现

最近项目需要用到线程池,以前没接触过,断断续续学了两三个星期吧

先在网上找了一个用C实现的,例子挺多,不过我只看了一个

http://www.linuxidc.com/Linux/2013-01/77619.htm

我觉得写得比较简洁易懂

项目是C++写的,用的ACE框架,而且系统不算小,如果直接用C的话可能会破坏系统原有的封装和扩展性

可能会用ACE的ACE_TASK来实现线程池,但在此之前我想先自学一下基于pthread的C++的线程池实现

在网上也找到挺多C++的例子,不过都不全,有下到一个源码(网址忘记保存了,下次找到再补上)但完全没有讲解,就自己仿着重写了一个

声明:本文适合用过pthread和一定的C++面向对象编程经验的人。本人菜鸟,难免错漏,望能指正

本代码在Ubuntu12.04下用Eclipse for c++编写,编译的时候需要添加pthread的库

由于代码比较多,因此我先贴一个大致的流程图上来

1.在main函数中新建一个MyThreadPool对象,并对其进行初始化,新建N个子线程

2.子线程里面循环判断成员m_pJob是否为空,不为空则向下执行,运行m_pJob完毕后让该子线程从BusyList移到IdleList

3.main函数中新建Job对象(你真正想运行的东西),并把它加入线程池中,并与某子线程绑定,同时让该子线程从IdleList移到BusyList

小结一句:其实在线程池中Busy与Idle线程的本质区别是其成员job是否为空

代码本来不算多,但因为有多个类,所以看起来会比较辛苦,先贴上类图

接下来正式贴代码,注释不多,但也不复杂

代码比较多,但重点看MyThread,MyWorkThread和MyThreadPool这3个类就行了

首先是MyThread类

MyThread.h

#ifndef MYTHREAD_H_
#define MYTHREAD_H_

#include
#include “pthread.h”

class MyThread {

public:
 MyThread();
 virtual ~MyThread();
 virtual void Run(void) = 0;

 bool  Create(MyThread* thread);

 unsigned long  GetThreadID(void){return m_ThreadID;}

protected:
 

setTimeout()。Js的伪多线程

首先为什么说setTimeout()是多线程。因为我在顺序执行流程的时候,我可以把一部分耗时间,但又不需要及时处理的代码放到setTimeout()中去执行。即空闲时间去执行。为什么说是空闲时间呢。可以写一个小dome测试一下。



#1那里耗了100ms.setTimeout()是50ms.如果是严格的50ms后执行应该在循环里就执行了。但实际结果是先执行的#2。

以下是执行结果。

687fininsh671

687-671=16.这说明。setTimeout()当时就开始计时了。当时间到了的时候并不是马上执行。而是看有没有其它操作。在确定没有其它操作后才真正的执行代码的。这样就可以把一些耗时间的操作放到空闲时处理,以提高代码效率。

为什么说setTimeout是伪多线程呢。是因为实际还是单线程操作的。再看下一个demo




由于#2基本上不耗时间。write()故意耗掉100ms.

执行结果:

15in953125

执行流程是#1计时开始。#2执行。#3计时开始。#1时间到。发现是空余时间,执行。#1执行过程中,#3时间到。(如果确实是多线程,这时候#3应该也要开始执行了。)实际上。#3发现有代码在执行,等待,直到#1执行完。#3开始执行。可见#1,#3的时间差应该就是一个write()耗的时间数。125-15=110也说明了确实是这样。

用setTimeout的好处就是把代码扔到了空余时间处理。这在处理并发问题时很有用。假设这样一种应用。我服务器往客户端抛数据。客户端接受数据时马上处理。如果服务器是每1ms抛一条数据。而js处理这条数据要两2ms.显然会有数据的丢失,或称为数据淹没。光是这种应用就会丢失50%的数据。事实上如果js处理数据是往DOM上加结点的话。js的耗时会越来越多,越往后丢失的数据越多。处理这种问题就是应用setTimeout().数据来时,我直接抛走。真正的执行是在空闲时间再做。这样就不会有数据丢失了!

现在在做的NBA体育文字直播之前没有用settimeout。所以出现了数据丢失的问题。一百多个用户。实际只处理了30来位。丢失了70%。现在改为setTimeout来做。效果如何,我也试目以待。

Linux系统入门学习:在 Linux 中统计一个进程的线程数

问题: 我正在运行一个程序,它在运行时会派生出多个线程。我想知道程序在运行时会有多少线程。在 Linux 中检查进程的线程数最简单的方法是什么?

如果你想看到 Linux 中每个进程的线程数,有以下几种方法可以做到这一点。

 

方法一: /proc

proc 伪文件系统,它驻留在 /proc 目录,这是最简单的方法来查看任何活动进程的线程数。 /proc 目录以可读文本文件形式输出,提供现有进程和系统硬件相关的信息如 CPU、中断、内存、磁盘等等.

  1. $ cat/proc/<pid>/status

上面的命令将显示进程 的详细信息,包括过程状态(例如, sleeping, running),父进程 PID,UID,GID,使用的文件描述符的数量,以及上下文切换的数量。输出也包括进程创建的总线程数如下所示。

  1. Threads:<N>

例如,检查 PID 20571进程的线程数:

  1. $ cat/proc/20571/status

输出表明该进程有28个线程。

或者,你可以在 /proc//task 中简单的统计子目录的数量,如下所示。

  1. $ ls/proc/<pid>/task |wc

这是因为,对于一个进程中创建的每个线程,在 /proc//task 中会创建一个相应的目录,命名为其线程 ID。由此在 /proc//task 中目录的总数表示在进程中线程的数目。

 

方法二: ps

如果你是功能强大的 ps 命令的忠实用户,这个命令也可以告诉你一个进程(用“H”选项)的线程数。下面的命令将输出进程的线程数。“h”选项需要放在前面。

  1. $ ps hH p <pid>|wc-l

如果你想监视一个进程的不同线程消耗的硬件资源(CPU & memory),请参阅此教程


via: http://ask.xmodulo.com/number-of-threads-process-linux.html

作者:Dan Nanni 译者:strugglingyouth 校对:wxy

本文由 LCTT 原创翻译,Linux中国 荣誉推出

测试多线程下载的Java类

Java多线程下载的基础类,类似于迅雷,QQ旋风等下载器一样的原理。
 
package com.shenzhen.mutiledownload2014;
 
import java.io.InputStream;
 import java.io.RandomAccessFile;
 import java.net.HttpURLConnection;
 import java.net.URL;
 
/**
  * 测试多线程下载的样例
  *
 * @author mayubao
  *
 */
 public class TestDownload {
 
    public static final String path = “http://192.168.1.120:8080/a.zip”;
 
    public static final void main(String[] args) throws Exception {
        URL url = new URL(path);
        HttpURLConnection conn = (HttpURLConnection) url.openConnection();// 打开一个链接
 
        // 设置一个请求的相关信息
        conn.setRequestMethod(“GET”);
        conn.setConnectTimeout(5000);
        // User-Agent Mozilla/5.0 (Windows NT 6.1; WOW64; rv:29.0)
        // Gecko/20100101 Firefox/29.0
 
        conn.setRequestProperty(“User-Agent”,
                “Mozilla/5.0 (Windows NT 6.1; WOW64; rv:29.0) Gecko/20100101 Firefox/29.0”);
 
        int code = conn.getResponseCode();
 
        if (code == 200) {// 请求过去且回复内容正常的话
            int len = conn.getContentLength();
            RandomAccessFile file = new RandomAccessFile(“D:/temp/test/”
                    + getFileName(path), “rwd”);
 
            // 1.创建一个本地文件跟服务器的大小一致
            file.setLength(len);
 
            // 2.根据服务器中要下载的文件大小划分要多少个线程
            int threadnum = 3;
            int blocksize = len / threadnum;
 
            /**
              * 多线程下载 线程1 0 ~ blocksize 线程2 blocksize*1 ~ blocksize*2 线程3
              * blocksize*2 ~ len
              */
            for (int i = 0; i < threadnum; i++) {
                int startposition = i * blocksize;
                int endposition = (i + 1) * blocksize;
                if (i == (threadnum – 1)) {// 最后一个线程的话,那么就另endposition=len
                    endposition = len;
                }
 
                // 分别执行每一个线程
 
                new DownloadTask(i, path, startposition, endposition).start();
            }
 
        }
        // conn.setRequestProperty(key, value);
 
    }
 
    public static String getFileName(String path) {
        int start = path.lastIndexOf(“/”);
        return path.substring(start, path.length());
    }
 
}
 

/**
  * 下载的线程类
  *
 * @author mayubao
  *
  */
 class DownloadTask extends Thread {
 
    private int id;
    private String path;
    private int startposition;
    private int endposition;
 
    public DownloadTask(int id, String path, int startposition, int endposition) {
        this.id = id;
        this.path = path;
        this.startposition = startposition;
        this.endposition = endposition;
    }
 
    @Override
    public void run() { // 每一个线程体要执行的内容
        URL url;
        try {
            url = new URL(path);
            HttpURLConnection conn = (HttpURLConnection) url.openConnection();
 
            // 设置一个请求的相关信息
            conn.setRequestMethod(“GET”);
            conn.setConnectTimeout(5000);
            // User-Agent Mozilla/5.0 (Windows NT 6.1; WOW64; rv:29.0)
            // Gecko/20100101 Firefox/29.0
 
            conn.setRequestProperty(“User-Agent”,
                    “Mozilla/5.0 (Windows NT 6.1; WOW64; rv:29.0) Gecko/20100101 Firefox/29.0”);
 
            InputStream is = conn.getInputStream();
            RandomAccessFile file = new RandomAccessFile(getFileName(path),
                    “rwd”);
 
            file.seek(startposition);
 
            // 将反馈回来的输入流写到RandomAccessFile里面去
            byte[] buffer = new byte[1024];
            int len = 0;
 
            while ((len = is.read(buffer)) != -1) {// 输入流没到尽头
                file.write(buffer, 0, len);
            }
 
            file.close();
 
            System.out.println(“第” + id + “个线程已经下载完成了”);
 
        } catch (Exception e) {
            e.printStackTrace();
        }
        super.run();
    }
 
    public static String getFileName(String path) {
        int start = path.lastIndexOf(“/”);
        return path.substring(start, path.length());
    }
 
}

Java1.5后的多线程框架 http://www.linuxidc.com/Linux/2014-02/96879.htm

Java多线程和同步的理解 http://www.linuxidc.com/Linux/2013-12/93691.htm

Java中两种实现多线程方式的对比分析 http://www.linuxidc.com/Linux/2013-12/93690.htm

Java利用多线程计算目录数据大小 http://www.linuxidc.com/Linux/2013-09/90715.htm

Java多线程向数据库写入数据 http://www.linuxidc.com/Linux/2013-09/90297.htm

Java多线程经典案例 http://www.linuxidc.com/Linux/2014-06/103458.