semaphore可以实现对同一资源的访问控制。
semaphore有三种基本操作。new()方法可以创建一个带单个或多个钥匙的semaphore, 使用get()可以获取一个或者多个钥匙,而put()可以返回一个或者多个钥匙。
一
如果试图获取一个semaphore而希望不被阻塞,可以使用try_get()函数,它返回1表示有足够多的钥匙,而返回0则表示钥匙不够。
- program automatic test(bus_ifc.TB bus);
- semaphore sem; //创建一个semaphore
- initial begin
- sem = new(l); //分配一个钥匙
- fork
- sequencer(); / /产生两个总线事务线程
- sequencer();
- join
- end
-
- task sequencer;
- repeat($urandom%10) //随机等待0-9个周期
- @bus.cb;
- sendTrans(); //执行总线事务
- endtask
-
- task sendTrans;
- sem.get(1); //获取总线钥匙
- @bus.cb; //把信号驱动到总线上
- bus.cb.addr <= t.addr;
- ...
- sem.put(l); //处理完成时把钥匙返回
- endtask
- endprogram
控制共享资源的原因在于,如果不对其访问做控制,可能会出现多个线程对同一资源的访问,进而导致不可预期的数据损坏和线程的异常,这种现象称之为“线程不安全”。
- class car;
- semaphore key;
- function new();
- key = new(l);
- endfunction
- task get_on(string p);
- $display("%s is waiting for the key", p);
- key.get();
- #lns;
- $display ("%s got on the car", p);
- endtask
- task get_off(string p);
- $display("%s got off the car", p);
- key.put();
- #lns;
- $display ("%s returned the key", p);
- endtask
- endclass
-
- module family;
- car byd = new();
- string pl = "husband";
- string p2 = "wife";
- initial begin
- fork
- begin//丈夫开车
- byd.get_on(pl);
- byd.get_off(pl);
- end
-
- begin//妻子开车
- byd.get_on(p2);
- byd.get_off(p2);
- end
- join
- end
- endmodule
# husband is waiting for the key
# wife is waiting for the key
# husband got on the car
# husband got off the car
# husband returned the key
# wife got on the car
# wife got off the car
# wife returned the key&1:一开始在拿到这辆车的时候,只有一把钥匙,而丈夫和妻子如果都想开车的话,也得遵循先到先得的原则。所以,当丈夫和妻子同时都想用车的时候,一把钥匙只能交给他们中的一位,另外一位则需要等待,直到那把钥匙归还之后才可以使用。
&2:从上面的输出结果来看,也是能够看出来,虽然丈夫和妻子在同一时间想开这辆车,然而也只能允许一位家庭成员来驾驶。直到丈夫从车上下来,归还了钥匙以后,妻子才可以上车。
&3:这个生动的例子解释了semaphore对于控制访问共享资源的帮助,从上semaphore key的使用来看,key在使用前必须要做初始化,即要告诉用户它原生自带几把钥匙。
&4:从例子来看,它只有1把钥匙,而丈夫和妻子在等待和归还钥匙时,没有在semaphore ::get()/put()函数中传递参数,即默认他们等待和归还的钥匙数量是1。semaphore可以被初始化为多个钥匙,也可以支持每次支取和归还多把钥匙用来控制资源访问。&5:那么如果上面的semaphore, 用自定义的类来实现,该怎么做呢?
- class carkeep;
- int key= 1;
- string q[$];
- string user;
-
- task keep_car();
- fork
- forever begin//管理钥匙和分发
- wait(q. size() != 0 && key != 0);
- user = q.pop_front();
- key--;
- end
- join_none;
- endtask
-
- task get_key(string p); //拿钥匙
- q.push_back(p);
- wait(user= p);
- endtask
-
- task put_key(string p); //还钥匙
- if(user = p) begin
- user= "none";
- key++;
- end
- endtask
- endclass
-
- class car;
- carkeep keep;
- function new();
- keep= new();
- endfunction
-
- task drive() ;
- keep.keep_car();
- endtask
-
- task get_on (string p);
- $display("%s is waiting for the key", p);
- keep.get_key(p);
- #lns;
- $display("%s got on the car", p) ;
- endtask
-
- task get_off(string p);
- $display("%s got off the car", p) ;
- keep.put_key(p);
- #lns;
- $display("%s returned the key", p);
- endtask
- endclass
-
- module family;
- car byd = new();
- string pl = "husband";
- string p2 = "wife";
- initial begin
- fork
- begin//丈夫开车
- byd.get_on(pl);
- byd.get_off(pl);
- end
-
- begin//妻子开车
- byd.get_on(p2);
- byd.get_off(p2);
- end
- join
- end
- endmodule
# husband is waiting for the key
# wife is waiting for the key
# husband got on the car
# husband got off the car
# husband returned the key
# wife got on the car
# wife got off the car
# wife returned the key这对夫妻除了有一辆车之外,还添加了一个智能车管家carkeep,这个管家的作用使得夫妻不在因为车到底该给谁开而惹得让人不开心,他会公平地保管,分发和回收钥匙。