顾福源 发表于 2016-8-27 21:11:15

开贴,不定期对Linux下的编程进行更新

毕业后毅然跳进了linux环境下编程的坑里面,好多东西从头开始学,在论坛里面开个帖子,留下学习笔记。资料传送门:链接:http://pan.baidu.com/s/1kV2hm2V 密码:0bub;

程浥 发表于 2016-8-28 14:30:14

大神 带我 装逼 带我飞

顾福源 发表于 2016-9-2 21:46:19

在集成的IDE环境下面,编辑好工程代码以后只需要点击build等编译的按键,IDE就能为我们完成代码的编译、链接等工作。如果没有集成开发环境呢,就得使makefile了,自己在makefile中写好编译的规则,然后执行make开始编译。
makefile的规则:
        target ... : prerequisites ...
        command
        ...
        ...
target也就是一个目标文件,可以是Object File,也可以是执行文件。还可以是一个标签(Label);
prerequisites就是,要生成那个target所需要的文件或是目标;
command也就是make需要执行的命令。(任意的Shell命令);
这是一个文件的依赖关系,也就是说,target这一个或多个的目标文件依赖于prerequisites中的文件,其生成规则定义在command中。说白一点就是说,prerequisites中如果有一个以上的文件比target文件要新的话,command所定义的命令就会被执行。这就是Makefile的规则。也就是Makefile中最核心的内容。
举个例子:想编译得到aaa的文件,代码有main.c和test.c,main.c中引用了a.h和b.h,test.c中引用了c.h,那么就有如下的makefile文件:
aaa : main.o test.o
gcc -o aaa main.o test.o

main.o : main.c a.h b.h
gcc -c main.c

test.o : test.c c.h d.h
gcc -c test.c

clean:
        rm main.o test.o
上述例子能完成一个简单的编译动作,但是一旦aaa所需要的依赖文件太多,这时就可以使用变量来代替依赖文件,达到简化的目的,修改如下:
#使用obj变量来表示依赖文件
obj = main.o test.o
gcc -o aaa $(obj)

main.o : main.c a.h b.h
gcc -c main.c

test.o : test.c c.h d.h
gcc -c test.c

clean:
        rm main.o test.o
于是如果有新的 .o 文件加入,我们只需简单地修改一下 obj 变量就可以了;
此makefile还可以继续简化,使用make的自动推导的功能,只要make看到一个[.o]文件,它就会自动的把[.c]文件加在依赖关系中,如果make找到一个whatever.o,那么whatever.c,就会是whatever.o的依赖文件。并且 cc -c whatever.c 也会被推导出来,于是进一步简化得:
obj = main.o test.o
gcc -o aaa $(obj)

main.o : main.c a.h b.h
test.o : test.c c.h d.h

.PHONY : clean
        rm main.o test.o
注意观察,这个makefile里面没有了类似于gcc -c xxx.c这样的语句了,这种方法,也就是make的“隐晦规则”。上面文件内容中,“.PHONY”表示,clean是个伪目标文件;

顾福源 发表于 2016-9-2 21:50:43

makefile基础的用法理解起来不难,但是makefile的功能远不止这么一点点,今天拿到公司的一个工程,打开makefile一看彻底就懵了,还是基础不够,makefile中提供的很多指令,在一个makefile中包含引用其他的makefile进行编译,功能之强大。。贡献一份找了半天的资料,简单易懂http://www.cnblogs.com/wang_yb/p/3990952.html

顾福源 发表于 2016-9-3 18:01:49

关于线程互斥的时候使用条件变量的研究
    百度百科的解释:条件变量是利用线程间共享的全局变量进行同步的一种机制,主要包括两个动作:一个线程等待"条件变量的条件成立"而挂起;另一个线程使"条件成立"(给出条件成立信号)。为了防止竞争,条件变量的使用总是和一个互斥锁结合在一起。(请注意这句话!否则你会纠结为什么当在一个线程中给出条件信号后,正在等待的线程不会立马响应这个条件)
    两个关键的函数pthread_cond_wait()和pthread_cond_signal(),前者用于在一个线程中告诉线程等待条件变量的到来,等待的过程线程将会处于阻塞状态,而后者则是在另外一个线程中激发某一个条件,告诉正在等待这个条件产生的线程你可以干活了。pthread_cond_wait()的函数原型为:int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex),可以看出来这和互斥锁mutex有关,这就是上面那句标红了的话的原因。按我们的思维来讲,当条件给出后应该要立马就去响应啊,但是如果这样的话就会对某些公共的资源(如全局变量)形成竞争!出现同时又两个或两个以上的线程对同一个资源进行操作,这是不允许的。为解决这一问题,于是将条件变量与互斥锁一起使用,双重保险,以避免多个线程同时操作一个资源的情况,即使条件已经给出来了,如果锁还没有被其他线程释放,那么线程将会继续等待。
举个例子:有一个全局变量i,thread1中将i从1自加到9,当i是3的倍数的时候就产生条件,即执行pthread_cond_signal;在thread2中判断i的情况,当i不为3的倍数的时候就等待,知道i为3的倍数的才执行操作。
给出代码:
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>   
#include <unistd.h>   
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; /*初始化互斥锁*/
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;    /*初始化条件变量*/   

void *thread1(void *); /*线程a函数声明*/
void *thread2(void *); /*线程b函数声明*/

int i=1;/*测试用的全局变量*/

int main(void)
{
      pthread_t t_a; /*线程a标识符*/
      pthread_t t_b; /*线程b标识符*/
      pthread_create(&t_a,NULL,thread1,(void *)NULL);/*创建进程t_a*/
      pthread_create(&t_b,NULL,thread2,(void *)NULL); /*创建进程t_b*/
      pthread_join(t_b, NULL);/*等待进程t_b结束*/
      pthread_mutex_destroy(&mutex);/*销毁互斥锁*/
      pthread_cond_destroy(&cond);    /*销毁条件变量*/
         exit(0);
}

void *thread1(void *junk)
{
      for(i=1;i<=9;i++){

                pthread_mutex_lock(&mutex);//
                if(i%3==0){
                        pthread_cond_signal(&cond);/*条件改变,发送信号,通知t_b进程*/
                }
                printf("thead1:%d\n",i);
                pthread_mutex_unlock(&mutex);//*解锁互斥量*/
                printf("Thread1 Up Unlock Mutex\n");
                sleep(1);
      }
}

void *thread2(void *junk)
{
      while(i<9)
      {
                pthread_mutex_lock(&mutex);

                if(i%3!=0) {
                        pthread_cond_wait(&cond,&mutex);/*等待*/
                }
                printf("thread2:%d\n",i);
                pthread_mutex_unlock(&mutex);
                printf("Thread2 Down Ulock Mutex\n");

                sleep(1);
      }
}
编译之后,执行可执行文件,得到如下的结果,可以看到屏幕上面基本是按顺序打印出来提示信息,就感觉好像是当thread1执行pthread_cond_signal(&cond)后,thread2就立马结束了阻塞状态进入到就绪态,再到执行状态。


但将thread1改成这样:
void *thread1(void *junk)
{
        for(i=1;i<=9;i++){
                pthread_mutex_lock(&mutex);//
                if(i%3==0){
                /*在执行pthread_cond_signal后,将线程休眠3秒后再将mutex解锁*/               
                        pthread_cond_signal(&cond);/*条件改变,发送信号,通知t_b进程*/
                        printf("cond_signal! now unlock mutex atter 3s\n");
                        sleep(3);
                        pthread_mutex_unlock(&mutex);//*解锁互斥量*/
                } else{
                        printf("thead1:%d\n",i);
                        pthread_mutex_unlock(&mutex);//*解锁互斥量*/
                        printf("Thread1 Up Unlock Mutex\n");
                }
                /*为了观察现象,每次循环都将线程休眠5秒*/         
                sleep(5);
        }
}

将i是3的倍数和不是3的倍数的两种情况分开,分别执行解锁操作pthread_mutex_unlock(&mutex),重新编译后,再执行程序,可以看到在i为3的倍数的情况下,执行了pthread_cond_signal(&cond)之后,thread2并没有立马打印出信息,而是在thread1执行pthread_cond_signal(&cond)后,在睡眠3秒,最后执行完了pthread_mutex_unlock(&mutex),将mutex从thread1中解锁后,thread2才从阻塞态退出的。


李维强-15级 发表于 2016-9-4 03:05:17

C语言就是一个坑 ,用起来确实麻烦。。。
只不过也 把你那个搞通透了,看我们这些什么前端后端就是helloWord啊

李维强-15级 发表于 2016-9-4 03:08:22

顾福源 发表于 2016-9-3 18:01
关于线程互斥的时候使用条件变量的研究
    百度百科的解释:条件变量是利用线程间共享的全局变量进行同步 ...

线程互斥这个,在C++里面有几种方式一般用互斥信号,或者关键代码段来标明要访问的公用变量是不是正在被其他线程占用。。反正意思就是标明其他代码不能访问这个公用变量

顾福源 发表于 2016-9-4 13:25:56

李维强-15级 发表于 2016-9-4 03:05
C语言就是一个坑 ,用起来确实麻烦。。。
只不过也 把你那个搞通透了,看我们这些什么前端后端就是helloWo ...

其实重点还是在操作系统、数据结构及算法原理这些方面

顾福源 发表于 2016-9-4 19:45:15

两种文件系统的区别
当在程序中需要时使用文件系统打开文件时,程序员会在open()和fopen()这两个函数中选择一个来打开文件,虽然这两个函数都能打开文件,但是后者(fopen)为缓冲文件系统,缓冲文件系统的特点是:在内存开辟一个“缓冲区”,为程序中的每一个文件使用,当执行读文件的操作时,从磁盘文件将数据先读入内存“缓冲区”, 装满后再从内存“缓冲区”依此读入接收的变量。执行写文件的操作时,先将数据写入内存“缓冲区”,待内存“缓冲区”装满后再写入文件。缓冲件系统的函数还包括fopen, fclose, fread, fwrite, fgetc, fgets, fputc, fputs, freopen, fseek, ftell, rewind等;
而open系列的函数则没有缓冲区,借助文件结构体指针来对文件进行管理,通过文件指针来对文件进行访问,既可以读写字符、字符串、格式化数据,也可以读写二进制数 据。非缓冲文件系统依赖于操作系统,通过操作系统的功能对文件进行读写,是系统级的输入输出,它不设文件结构体指针,只能读写二进制文件,但效率高、速度快,由于ANSI标准不再包括非缓冲文件系统,因此建议大家最好不要选择它。
页: [1]
查看完整版本: 开贴,不定期对Linux下的编程进行更新