文档章节

linux线程阐述

 每天在改变
发布于 2017/01/15 20:15
字数 4678
阅读 31
收藏 1
点赞 0
评论 0

9.1进程回顾

9.1.1多进程实现同时读取键盘和鼠标

注意:进程相关函数:fork()。

代码如下:

#include <stdio.h>

#include <unistd.h>

#include <string.h>

#include <sys/types.h>

#include <sys/stat.h>

#include <fcntl.h>

int main(void)

{

// 创建子进程,然后父子进程中分别进行读键盘和鼠标的工作

int ret = -1;

int fd = -1;

char buf[200];

 

ret = fork();

if (ret == 0)

{

// 子进程

fd = open("/dev/input/mouse1", O_RDONLY);

if (fd < 0)

{

perror("open:");

return -1;

}

 

while (1)

{

memset(buf, 0, sizeof(buf));

printf("before read.\n");

read(fd, buf, 50);

printf("读出鼠标的内容是:[%s].\n", buf);

}

}

else if (ret > 0)

{

// 父进程

while (1)

{

memset(buf, 0, sizeof(buf));

printf("before read.\n");

read(0, buf, 5);

printf("读出键盘的内容是:[%s].\n", buf);

}

}

else

{

perror("fork:");

}

 

return 0;

}

运行结果:

 

当鼠标移动出现如下画面:

 

键盘按下:

 

9.1.2使用进程技术的优势

(1)CPU时分复用,单核心CPU可以实现宏观上的并行

(2)实现多任务系统需求(多任务的需求是客观的)

(3)程序的并发执行和资源共享。多道程序设计出现后,实现了程序的并发执行和资源共享,提高了系统的效率和系统的资源利用率。

4顺序程序的特点:具有封闭性和可再现性.

(5)每个进程互相独立,不影响主程序的稳定性,子进程崩溃没关系; 通过增加CPU,就可以容易扩充性能; 可以尽量减少线程加锁/解锁的影响,极大提高性能,就算是线程运行的模块算法效率低也没关系;

9.1.3进程技术的劣势

(1)进程间切换开销大

(2)进程间通信麻烦而且效率低

3逻辑控制复杂,需要和主程序交互; 需要跨进程边界,如果有大数据量传送,就不太好,适合小数据量传送、密集运算 多进程调度开销比较大;

 

 

9.1.4线程技术对比

特点:

(1)线程技术保留了进程技术实现多任务的特性。

(2)线程的改进就是在线程间切换和线程间通信上提升了效率。

(3)多线程在多核心CPU上面更有优势。

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

 

9.2线程技术的引入

9.2.1 什么是线程?

1相对进程而言,线程是一个更加接近于执行体的概念,它可以与同进程中的其他线程共享数据,但拥有自己的栈空间,拥有独立的执行序列。在串行程序基础上引入线程和进程是为了提高程序的并发度,从而提高程序运行效率和响应时间。 

(2)一种轻量级进程

(3)线程是参与内核调度的最小单元

(4)一个进程中可以有多个线程 

9.2.1线程的创建

POSIX通过pthread_create()函数创建线程,API定义如下:  
    int pthread_create(pthread_t * thread, pthread_attr_t * attr, void * (*start_routine)(void *), void * arg)  

9.2.2使用线程技术同时读取键盘和鼠标

代码如下:

#include <stdio.h>

#include <unistd.h>

#include <string.h>

#include <sys/types.h>

#include <sys/stat.h>

#include <fcntl.h>

#include <pthread.h>

char buf[200];

void *func(void *arg)

{

while (1)

{

memset(buf, 0, sizeof(buf));

printf("before read.\n");

read(0, buf, 5);

printf("读出键盘的内容是:[%s].\n", buf);

}

 

}

int main(void)

{

// 思路就是创建子进程,然后父子进程中分别进行读键盘和鼠标的工作

int ret = -1;

int fd = -1;

pthread_t th = -1;

ret = pthread_create(&th, NULL, func, NULL);

if (ret != 0)

{

printf("pthread_create error.\n");

return -1;

}

// 因为主线程是while(1)死循环,所以可以在这里pthread_detach分离子线程

// 主任务

fd = open("/dev/input/mouse1", O_RDONLY);

if (fd < 0)

{

perror("open:");

return -1;

}

while (1)

{

memset(buf, 0, sizeof(buf));

printf("before read.\n");

read(fd, buf, 50);

printf("读出鼠标的内容是:[%s].\n", buf);

}

return 0;

}

注意:编译时候不要忘记-lpthread。

运行结果:

 

鼠标与键盘结果和进程结果相同。

9.2.3线程简单图形理解(以上面程序为参考)


注意:线程是依赖于进程。以上面代码为列:注意:此流程图由于线程回收等新内容(上面程序并没有写到),流程图并不完整,后面会涉及到。

注意:线程是依赖于进程。以上面代码为列:

 
所以:没有进程也就没有线程,*func线程结束并不影响,进程结束所有线程结束。  

9.3线程基本函数

 

9.3.1线程创建与回收

(1) pthread_create      主线程用来创造子线程的

(2) pthread_join      主线程用来等待(阻塞)回收子线程

(3) pthread_detach  主线程用来分离子线程,分离后主线程不必再去回收子线程

9.3.2线程取消

 

(1) pthread_cancel        一般都是主线程调用该函数去取消(让它赶紧死)子线程

(2) pthread_setcancelstate 子线程设置自己是否允许被取消

(3) pthread_setcanceltype

 

注意:

(1)int pthread_cancel(pthread_t thread) 。thread:线程号,创建时定义的线程号。(如果子线程允许取消)。

(2)int pthread_setcancelstate(int state, int *oldstate);子线程默认是可以取消。

 1.PTHREAD_CANCEL_ENABLE可以取消。

 2.PTHREAD_CANCEL_DISABLE不允许取消。

(3)int pthread_setcanceltype(int type, int *oldtype);取消类型

 1.PTHREAD_CANCEL_DEFERRED立即取消。

 2.PTHREAD_CANCEL_ASYNCHRONOUS不立即等待合适时刻取消

 

9.3.3线程函数退出相关

 

(1) pthread_exit与return 线程退出        pthread_exit标准子线程退出

(2) pthread_cleanup_push

(3) pthread_cleanup_pop

 

 

 

void pthread_exit(void *retval);*retval:退出时返回的值。

void pthread_cleanup_push(void (*routine)(void *),void *arg);

void pthread_cleanup_pop(int execute);

 

线程终止有两种情况:正常终止和非正常终止。非正常终止情况下如果遇见在子线程取消情况下有互斥锁(后面讲到),会出现死锁,所以会用pthread_cleanup_push,pthread_cleanup_pop清理函数

 

注意:在下面三种情况下,pthread_cleanup_push()压栈的“清理函数”会被调用:
1, 线程调用pthread_exit()函数,而不是直接return.
2, 响应取消请求时,也就是有其它的线程对该线程调用pthread_cancel()函数。
3, 本线程调用pthread_cleanup_pop()函数,并且其参数非0
4当pthread_cleanup_pop()函数的参数为0时,仅仅在线程调用pthread_exit函数或者其它线程对本线程调pthread_cancel函数时,才在弹出“清理函数”的同时执行该“清理函数”。
5注意pthread_exit终止线程与线程直接return终止线程的区别,调用return函数是不会在弹出“清理函数”的同时执行该“清理函数的。
6.pthread_cleanup_push()函数与pthread_cleanup_pop()函数必须成对的出现在同一个函数中。

参考部分程序:

/*清理的函数体*/

static void cleanup_handler(void *arg)

{

        printf("Called clean-up handler\n");

         cnt = 0;

}

 /*子进程*/

static void *thread_start(void *arg)

{

         time_t start, curr;

        printf("New thread started\n");

 

        pthread_cleanup_push(cleanup_handler, NULL);

 

        curr = start = time(NULL);

        while(!done){

                pthread_testcancel(); 

                if(curr < time(NULL)){

                        curr = time(NULL);

                        printf("cnt= %d\n", cnt);                        cnt++;

                }

        }

 

        pthread_cleanup_pop(1);

        return NULL;

}

9.3.4获取线程id

 pthread_t pthread_self(void);获取子线程的ID号

 

9.4  线程同步之信号量

9.4.1基本函数

 

int sem_init (sem_t *sem, int pshared, unsigned int value);

sem指定的信号量进行初始化,设置好它的共享选项,并指定一个整数类型的初始值。

 

int sem_wait(sem_t * sem);  

函数sem_wait( sem_t *sem )被用来阻塞当前线程直到信号量sem的值大于0,解除阻塞后将sem的值减一,表明公共资源经使用后减少。函数sem_trywait ( sem_t *sem )是函数sem_wait()的非阻塞版本,它直接将信号量sem的值减一。 

 

int sem_post(sem_t * sem);  

函数sem_post( sem_t *sem )用来增加信号量的值。当有线程阻塞在这个信号量上时,调用这个函数会使其中的一个线程不在阻塞,选择机制同样是由线程的调度策略决定的。

 

 int sem_destroy(sem_t *sem);

函数的作用是在我们用完信号量对它进行清理。

 

9.4.2信号量程序实现

任务:使用多线程实现:用户从终端输入任意字符然后统计个数显示,输入end则结束。主线程获取用户输入并判断是否退出,子线程计数。

参考程序:

#include <stdio.h>

#include <string.h>

#include <stdlib.h>

#include <pthread.h>

#include <semaphore.h>

char buf[200] = {0};

sem_t sem;

unsigned int flag = 0;

// 子线程程序,作用是统计buf中的字符个数并打印

void *func(void *arg)

{

// 子线程首先应该有个循环

// 循环中阻塞在等待主线程激活的时候,子线程被激活后就去获取buf中的字符

// 长度,然后打印;完成后再次被阻塞

sem_wait(&sem);

while (flag == 0)

{

printf("本次输入了%d个字符\n", strlen(buf));

memset(buf, 0, sizeof(buf));

sem_wait(&sem);

}

 

 

pthread_exit(NULL);

}

int main(void)

{

int ret = -1;

pthread_t th = -1;

sem_init(&sem, 0, 0);

ret = pthread_create(&th, NULL, func, NULL);

if (ret != 0)

{

printf("pthread_create error.\n");

exit(-1);

}

printf("输入一个字符串,以回车结束\n");

while (scanf("%s", buf))

{

// 去比较用户输入的是不是end,如果是则退出,如果不是则继续

if (!strncmp(buf, "end", 3))

{

printf("程序结束\n");

flag = 1;

sem_post(&sem);

//exit(0);

break;

}

// 主线程在收到用户收入的字符串,并且确认不是end后

// 就去发信号激活子线程来计数。

// 子线程被阻塞,主线程可以激活,这就是线程的同步问题。

// 信号量就可以用来实现这个线程同步

sem_post(&sem);

}

// 回收子线程

printf("等待回收子线程\n");

ret = pthread_join(th, NULL);

if (ret != 0)

{

printf("pthread_join error.\n");

exit(-1);

}

printf("子线程回收成功\n");

sem_destroy(&sem);

return 0;

}

程序运行结果:

 

 

9.5  线程同步之互斥锁

 

9.5.1 什么是互斥锁?

是一种特殊的信号量,常用来防止两个进程或线程在同一时刻访问相同的共享资源。互斥量来保证对变量(关键的代码段)的排他性访问。

 

9.5.2基本函数

 

(1)初始化互斥锁

 

int  pthread_mutex_init(pthread_mutex_t *mp, const pthread_mutexattr_t *mattr)

参数说明:mp 互斥锁地址    mattr  属性 通常默认 null

注意:初始化互斥锁之前,必须将其所在的内存清零。

 

(2)互斥锁锁定

 

int pthread_mutex_lock(pthread_mutex_t *mutex); #include pthread_mutex_t mutex; int ret; ret = pthread_ mutex_lock(&mp); /* acquire the mutex */

参数说明:

当 pthread_mutex_lock() 返回时,说明该互斥锁已被锁定,如果该互斥锁已被另一个线程锁定和拥有,就会调用线程将被阻塞,直到该互斥锁变为可用为止。

如果互斥锁类型为 PTHREAD_MUTEX_NORMAL,则不提供死锁检测。尝试重新锁定互斥锁会导致死锁。如果某个线程尝试解除锁定的互斥锁不是由该线程锁定或未锁定,则将产生不确定的行为。

如果互斥锁类型为 PTHREAD_MUTEX_ERRORCHECK,则会提供错误检查。如果某个线程尝试重新锁定的互斥锁已经由该线程锁定,则将返回错误。如果某个线程尝试解除锁定的互斥锁不是由该线程锁定或者未锁定,则将返回错误。

如果互斥锁类型为 PTHREAD_MUTEX_RECURSIVE,则该互斥锁会保留锁定计数这一概念。线程首次成功获取互斥锁时,锁定计数会设置为 1。线程每重新锁定该互斥锁一次,锁定计数就增加 1。线程每解除锁定该互斥锁一次,锁定计数就减小 1。 锁定计数达到 0 时,该互斥锁即可供其他线程获取。如果某个线程尝试解除锁定的互斥锁不是由该线程锁定或者未锁定,则将返回错误。

如果互斥锁类型是 PTHREAD_MUTEX_DEFAULT,则尝试以递归方式锁定该互斥锁将产生不确定的行为。对于不是由调用线程锁定的互斥锁,如果尝试解除对它的锁定,则会产生不确定的行为。如果尝试解除锁定尚未锁定的互斥锁,则会产生不确定的行为。

函数的返回值:

成功返回0,返回EAGAIN时超出了互斥锁递归锁定的最大次数无法上锁,返回EDEADLK时已经拥有互斥锁。

 

(3)互斥锁解除锁定

 

int pthread_mutex_unlock(pthread_mutex_t *mutex); #include pthread_mutex_t mutex; int ret; ret = pthread_mutex_unlock(&mutex); /* release the mutex */

说明:释放 mutex 引用的互斥锁对象。成功返回0,其他返回都为错误,

 

(4)互斥锁锁定的非阻塞方式

 

int pthread_mutex_trylock(pthread_mutex_t *mutex); #include pthread_mutex_t mutex; int ret; ret = pthread_mutex_trylock(&mutex); /* try to lock the mutex */

函数说明:pthread_mutex_trylock() 是 pthread_mutex_lock() 的非阻塞版本。

成功返回0,EBUSY :已经锁定,EAGAIN次数超限。

 

(5)互斥锁的销毁

 

int pthread_mutex_destroy(pthread_mutex_t *mp); #include pthread_mutex_t mp; int ret; ret = pthread_mutex_destroy(&mp); /* mutex is destroyed */

成功返回0,其它都为错误。

 

9.5.3代码实现:

实现内容:与信号量相同使用多线程实现:用户从终端输入任意字符然后统计个数显示,输入end则结束。主线程获取用户输入并判断是否退出,子线程计数。

参考代码:

#include <stdio.h>

#include <string.h>

#include <stdlib.h>

#include <pthread.h>

char buf[200] = {0};

pthread_mutex_t mutex;

unsigned int flag = 0;

// 子线程程序,作用是统计buf中的字符个数并打印

void *func(void *arg)

{

// 子线程首先应该有个循环

// 循环中阻塞在等待主线程激活的时候,子线程被激活后就去获取buf中的字符

// 长度,然后打印;完成后再次被阻塞

//while (strncmp(buf, "end", 3) != 0)

sleep(1);

while (flag == 0)

{

pthread_mutex_lock(&mutex);

printf("本次输入了%d个字符\n", strlen(buf));

memset(buf, 0, sizeof(buf));

pthread_mutex_unlock(&mutex);

sleep(1);

}

pthread_exit(NULL);

}

int main(void)

{

int ret = -1;

pthread_t th = -1;

pthread_mutex_init(&mutex, NULL);

ret = pthread_create(&th, NULL, func, NULL);

if (ret != 0)

{

printf("pthread_create error.\n");

exit(-1);

}

printf("输入一个字符串,以回车结束\n");

while (1)

{

pthread_mutex_lock(&mutex);

scanf("%s", buf);

pthread_mutex_unlock(&mutex);

// 去比较用户输入的是不是end,如果是则退出,如果不是则继续

if (!strncmp(buf, "end", 3))

{

printf("程序结束\n");

flag = 1;

 

//exit(0);

break;

}

sleep(1);

// 主线程在收到用户收入的字符串,并且确认不是end后

// 就去发信号激活子线程来计数。

// 子线程被阻塞,主线程可以激活,这就是线程的同步问题。

// 信号量就可以用来实现这个线程同步

}

// 回收子线程

printf("等待回收子线程\n");

ret = pthread_join(th, NULL);

if (ret != 0)

{

printf("pthread_join error.\n");

exit(-1);

}

printf("子线程回收成功\n");

pthread_mutex_destroy(&mutex);

return 0;

}

运行结果:

 

9.5.4本章注意问题:

当一个互斥量已经被别的线程锁定后,另一个线程调用pthread_mutex_lock()函数去锁定它时,会挂起自己的线程等待这个互斥量被解锁。可能出现以下两种情况:

“饥饿状态”:这个互斥量一直没有被解锁,等待锁定它的线程将一直被挂着,即它请求某个资源,但永远得不到它。用户必须在程序中努力避免这种“饥饿”状态出现。Pthread函数库不会自动处理这种情况。

“死锁”:一组线程中的所有线程都在等待被同组中另外一些线程占用的资源,这时,所有线程都因等待互斥量而被挂起,它们中的任何一个都不可能恢复运行,程序无法继续运行下去。这时就产生了死锁。Pthread函数库可以跟踪这种情形,最后一个线程试图调用pthread_mutex_lock()时会失败,并返回类型为EDEADLK的错误。

 

9.6  线程同步之条件变量

 

9.6.1什么是条件变量?

允许线程阻塞和等待另一个线程发送信号的方法弥补了互斥锁的不足,它常和互斥锁一起使用。

9.6.2基本函数

(1)条件变量初始化

int pthread_cond_init(pthread_cond_t *cond, const pthread_condattr_t *attr);

说明:cond  条件变量,attr  条件变量属性。成功返回0,出错返回错误编号。attr为空,它将使用缺省的属性来设置所指定的条件变量。

(2)条件变量摧毁

int pthread_cond_destroy(pthread_cond_t *cond);

说明:cond 条件变量,成功返回0,出错返回错误编号。

(3)条件变量等待

int pthread_cond_wait(pthread_cond_t *cond,pthread_mutex_t *mutex);

int pthread_cond_timedwait(pthread_cond_t *cond,pthread_mutex_t mytex,const struct timespec *abstime);

说明:cond 条件变量mutex 互斥锁。成功返回0,出错返回错误编号。*cond是指向一个条件变量的指针。*mutex则是对相关的互斥锁的指针。

 

pthread_cond_timedwait函数类型与函数pthread_cond_wait区别:

如果达到或是超过所引用的参数*abstime,它将结束并返回错误ETIME.pthread_cond_timedwait函数的参数*abstime指向一个timespec结构,阻塞等待时间。

该结构如下:

typedef struct timespec{

       time_t tv_sec;

       long tv_nsex;

}timespec_t;

 

(4)条件变量发送

int pthread_cond_signal(pthread_cond_t *cond);

int pthread_cond_broadcast(pthread_cond_t *cond);

说明:cond 条件变量,成功返回0,出错返回错误编号。调用pthread_cond_signal时一个在相同条件变量上阻塞的线程将被解锁,pthread_cond_broadcast通知阻塞在这个条件变量上的所有线程。

 

9.6.3代码实现

 

实现内容:与信号量相同使用多线程实现:用户从终端输入任意字符然后统计个数显示,输入end则结束。主线程获取用户输入并判断是否退出,子线程计数。

参考代码:

#include <stdio.h>

#include <string.h>

#include <stdlib.h>

#include <pthread.h>

char buf[200] = {0};

pthread_mutex_t mutex;

pthread_cond_t cond;

unsigned int flag = 0;

// 子线程程序,作用是统计buf中的字符个数并打印

void *func(void *arg)

{

while (flag == 0)

{

pthread_mutex_lock(&mutex);

pthread_cond_wait(&cond, &mutex);

printf("本次输入了%d个字符\n", strlen(buf));

memset(buf, 0, sizeof(buf));

pthread_mutex_unlock(&mutex);

}

pthread_exit(NULL);

}

int main(void)

{

int ret = -1;

pthread_t th = -1;

pthread_mutex_init(&mutex, NULL);

pthread_cond_init(&cond, NULL);

 

ret = pthread_create(&th, NULL, func, NULL);

if (ret != 0)

{

printf("pthread_create error.\n");

exit(-1);

}

printf("输入一个字符串,以回车结束\n");

while (1)

{

scanf("%s", buf);

pthread_cond_signal(&cond);

// 去比较用户输入的是不是end,如果是则退出,如果不是则继续

if (!strncmp(buf, "end", 3))

{

printf("程序结束\n");

flag = 1;

break;

}

}

// 回收子线程

printf("等待回收子线程\n");

ret = pthread_join(th, NULL);

if (ret != 0)

{

printf("pthread_join error.\n");

exit(-1);

}

printf("子线程回收成功\n");

pthread_mutex_destroy(&mutex);

pthread_cond_destroy(&cond);

 

return 0;

}

 

程序说明:当键盘输入字符后调用pthread_cond_signal(&cond);条件变量发送,子线程pthread_cond_wait(&cond, &mutex);由之前阻塞后执行后面代码。

程序运行结果:

 

9.7线程同步总结

一个大流程中实现的功能放到了多个小流程中,程序更加的简洁和易于阅读。提高了程序的执行效率。多线程”使得程序的模块化更强,有利于追踪程序执行过程和排查问题。线程同步是为了防止多个线程访问一个数据对象时,对数据造成破坏。线程的同步是保证多线程安全访问资源的一种手段。

 

© 著作权归作者所有

共有 人打赏支持
粉丝 0
博文 9
码字总数 13757
作品 0
淮安
大数据 | 主流Linux系统性能调优指南,你需要知道的这九点

大数据时代,除了基础配置和安装,需要性能调优的时候。不可能永远想着换硬件这么low的思想! 以下九点,为你阐述基础的调优概念,希望对你对你有益。 进程是什么? 进程就是执行程序运行在处...

黄色橙子 ⋅ 06/09 ⋅ 0

Linux压缩好帮手bzip2

导读 对文件进行压缩,可以通过使用较少的字节对文件中的数据进行编码来显著地减小文件的大小,并且在跨网络的文件的备份和传送时很有用。 另一方面,解压文件意味着将文件中的数据恢复到初始...

问题终结者 ⋅ 05/12 ⋅ 0

报名:《Linux的进程、线程以及调度》4节系列微课(5.22-25)

《Linux任督二脉-进程和内存》的第一脉——《Linux的进程、线程以及调度》,试图解决进程的生命周期、调度算法、多核负载均衡、Linux实时性等一系列的问题。之前已有400多位童鞋学习过《进程...

jus3ve ⋅ 05/12 ⋅ 0

深入理解load averages

前言 经常和Linux打交道的童鞋都知道,load averages是衡量机器负载的关键指标,但是这个指标是怎样定义出来的呢? 和其他系统不同,Linux上的load averages不仅追踪可运行的任务,还追踪处于...

大蟒传奇 ⋅ 05/30 ⋅ 0

Linux进程和线程间IPC机制

Linux进程间IPC 1.管道(Pipe)及有名管道(named pipe): 1、管道是半双工的,要实线读写需建立两根管道; 2、匿名管道用于父子进程或者兄弟进程之间(如forkexec创建的进程),命名管道允许没...

dodonei ⋅ 04/16 ⋅ 0

Linux内核学习笔记(四)进程管理

进程简介 进程(Process)是Unix操作系统最基本的抽象概念之一。进程是正在执行的程序,同时也是操作系统进行资源管理的最小单位,进程需要管理打开的文件、挂起的信号、内核内部数据、处理器...

damontive ⋅ 05/09 ⋅ 0

MySQL · 特性分析 · MySQL 8.0 资源组 (Resource Groups)

MySQL 8.0已经正式发布。这个版本包含很多有意思的特性,例如,更快、性能更好的Schema和Information Schema、原子DDL、UNDO空间回收等,在很多的网站,博客等上面都有大量的推广介绍。本文将...

db匠 ⋅ 05/22 ⋅ 0

嵌入式Linux学习基础规划篇

嵌入式的学习是需要日积月累的,是通过一点一滴的积累才能成为大神。下面来介绍一下嵌入式linux学习基础规划,目标是达到适应嵌入式应用软件开发、嵌入式系统开发或嵌入式驱动开发的基本素质...

创客学院 ⋅ 04/10 ⋅ 0

硬实时Linux(RT-Preempt Patch)在PC上的编译、使用和测试

xhe_href="http://weibo.com/21cnbao">by @宋宝华Barry Vanilla kernel的问题 Linux kernel在spinlock、irq上下文方面无法抢占,因此高优先级任务被唤醒到得以执行的时间并不能完全确定。同时...

21cnbao ⋅ 2012/10/03 ⋅ 0

Socket编程模式理解与对比

本文主要分析了几种Socket编程的模式。主要包括基本的阻塞Socket、非阻塞Socket、I/O多路复用。其中,阻塞和非阻塞是相对于套接字来说的,而其他的模式本质上来说是基于Socket的并发模式。I...

xumaojun ⋅ 05/01 ⋅ 0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

一篇文章学懂Shell脚本

Shell脚本,就是利用Shell的命令解释的功能,对一个纯文本的文件进行解析,然后执行这些功能,也可以说Shell脚本就是一系列命令的集合。 Shell可以直接使用在win/Unix/Linux上面,并且可以调用...

Jake_xun ⋅ 27分钟前 ⋅ 0

大数据工程师需要精通算法吗,要达到一个什么程度呢?

机器学习是人工智能的一个重要分支,而机器学习下最重要的就是算法,本文讲述归纳了入门级的几个机器学习算法,加大数据学习群:716581014一起加入AI技术大本营。 1、监督学习算法 这个算法由...

董黎明 ⋅ 今天 ⋅ 0

Kylin 对维度表的的要求

1.要具有数据一致性,主键值必须是唯一的;Kylin 会进行检查,如果有两行的主键值相同则会报错。 2.维度表越小越好,因为 Kylin 会将维度表加载到内存中供查询;过大的表不适合作为维度表,默...

无精疯 ⋅ 今天 ⋅ 0

58到家数据库30条军规解读

军规适用场景:并发量大、数据量大的互联网业务 军规:介绍内容 解读:讲解原因,解读比军规更重要 一、基础规范 (1)必须使用InnoDB存储引擎 解读:支持事务、行级锁、并发性能更好、CPU及...

kim_o ⋅ 今天 ⋅ 0

代码注释中顺序更改 文件读写换行

`package ssh; import com.xxx.common.log.LogFactory; import com.xxx.common.log.LoggerUtil; import org.apache.commons.lang3.StringUtils; import java.io.*; public class DirErgodic ......

林伟琨 ⋅ 今天 ⋅ 0

linux实用操作命令

参考 http://blog.csdn.net/qwe6112071/article/details/50806734 ls [选项] [目录名 | 列出相关目录下的所有目录和文件 -a 列出包括.a开头的隐藏文件的所有文件-A 同-a,但不列出"."和"...

简心 ⋅ 今天 ⋅ 0

preg_match处理中文符号 url编码方法

之前想过直接用符号来替换,但失败了,或者用其他方式,但有有些复杂,这个是一个新的思路,亲测可用 <?php$str='637朗逸·超速新风王(300)(白光)'; $str=iconv("UTF-8","GBK",$s...

大灰狼wow ⋅ 今天 ⋅ 0

DevOps 资讯 | PostgreSQL 的时代到来了吗 ?

PostgreSQL是对象-关系型数据库,BSD 许可证。拼读为"post-gress-Q-L"。 作者: Tony Baer 原文: Has the time finally come for PostgreSQL?(有删节) 近30年来 PostgreSQL 无疑是您从未听...

RiboseYim ⋅ 今天 ⋅ 0

github太慢

1:用浏览器访问 IPAddress.com or http://tool.chinaz.com 使用 IP Lookup 工具获得github.com和github.global.ssl.fastly.net域名的ip地址 2:/etc/hosts文件中添加如下格式(IP最好自己查一...

whoisliang ⋅ 今天 ⋅ 0

非阻塞同步之 CAS

为解决线程安全问题,互斥同步相当于以时间换空间。多线程情况下,只有一个线程可以访问同步代码。这种同步也叫阻塞同步(Blocking Synchronization). 这种同步属于一种悲观并发策略。认为只...

长安一梦 ⋅ 今天 ⋅ 0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部